LCOV - code coverage report
Current view: top level - src/engraving/rendering/score - measurelayout.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 84.1 % 1349 1135
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2023 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include <cfloat>
      23              : 
      24              : #include "measurelayout.h"
      25              : 
      26              : #include "iengravingconfiguration.h" // IWYU pragma: keep
      27              : 
      28              : #include "dom/ambitus.h"
      29              : #include "dom/barline.h"
      30              : #include "dom/beam.h"
      31              : #include "dom/factory.h"
      32              : #include "dom/keysig.h"
      33              : #include "dom/layoutbreak.h"
      34              : #include "dom/lyrics.h"
      35              : #include "dom/marker.h"
      36              : #include "dom/measure.h"
      37              : #include "dom/measurenumber.h"
      38              : #include "dom/measurerepeat.h"
      39              : #include "dom/mmrest.h"
      40              : #include "dom/mmrestrange.h"
      41              : #include "dom/part.h"
      42              : #include "dom/parenthesis.h"
      43              : #include "dom/spacer.h"
      44              : #include "dom/score.h"
      45              : #include "dom/staff.h"
      46              : #include "dom/stafflines.h"
      47              : #include "dom/system.h"
      48              : #include "dom/tie.h"
      49              : #include "dom/timesig.h"
      50              : #include "dom/tremolosinglechord.h"
      51              : #include "dom/tremolotwochord.h"
      52              : #include "dom/utils.h"
      53              : 
      54              : #include "editing/editkeysig.h"
      55              : #include "types/typesconv.h"
      56              : 
      57              : #include "arpeggiolayout.h"
      58              : #include "beamlayout.h"
      59              : #include "chordbracketlayout.h"
      60              : #include "chordlayout.h"
      61              : #include "horizontalspacing.h"
      62              : #include "layoutcontext.h"
      63              : #include "mmrestlayout.h"
      64              : #include "modifydom.h"
      65              : #include "parenthesislayout.h"
      66              : #include "restlayout.h"
      67              : #include "segmentlayout.h"
      68              : #include "slurtielayout.h"
      69              : #include "tlayout.h"
      70              : #include "tremololayout.h"
      71              : 
      72              : #include "log.h"
      73              : 
      74              : using namespace mu::engraving;
      75              : using namespace mu::engraving::rtti;
      76              : using namespace mu::engraving::rendering::score;
      77              : 
      78              : //---------------------------------------------------------
      79              : //   layout2
      80              : //    called after layout of page
      81              : //---------------------------------------------------------
      82              : 
      83        33503 : void MeasureLayout::layout2(Measure* item, LayoutContext& ctx)
      84              : {
      85        33503 :     assert(item->system());
      86        33503 :     assert(ctx.dom().nstaves() == item->mstaves().size());
      87              : 
      88        82235 :     for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
      89        48732 :         if (Spacer* sp = item->vspacerDown(staffIdx)) {
      90            2 :             TLayout::layoutSpacer(sp, ctx);
      91            2 :             double y = item->system()->staff(staffIdx)->y() + sp->staffOffsetY();
      92            2 :             sp->setPos(item->spatium() * .5, y + sp->staff()->staffHeight(item->tick()));
      93              :         }
      94        48732 :         if (Spacer* sp = item->vspacerUp(staffIdx)) {
      95            0 :             TLayout::layoutSpacer(sp, ctx);
      96            0 :             double y = item->system()->staff(staffIdx)->y() + sp->staffOffsetY();
      97            0 :             sp->setPos(item->spatium() * .5, y - sp->absoluteGap());
      98              :         }
      99              :     }
     100              : 
     101              :     // layout LAYOUT_BREAK elements
     102        33503 :     TLayout::layoutBaseMeasureBase(item, item->mutldata(), ctx);
     103              : 
     104              :     //---------------------------------------------------
     105              :     //    layout cross-staff ties
     106              :     //---------------------------------------------------
     107              : 
     108        49421 :     auto layoutCrossStaffTies = [](Chord* chord, Measure* item, const Fraction& stick, LayoutContext& ctx) ->void {
     109       108058 :         for (Note* note : chord->notes()) {
     110        58637 :             Tie* tieFor = note->tieFor();
     111        58637 :             Tie* tieBack = note->tieBack();
     112        58637 :             LaissezVib* lv = note->laissezVib();
     113        58637 :             if (lv && lv->isCrossStaff()) {
     114            0 :                 SlurTieLayout::layoutLaissezVibChord(chord, ctx);
     115              :             }
     116        58637 :             if (tieFor && !lv && tieFor->isCrossStaff()) {
     117            4 :                 SlurTieLayout::layoutTieFor(tieFor, item->system());
     118              :             }
     119        58637 :             if (tieBack && tieBack->tick() < stick && tieBack->isCrossStaff()) {
     120            0 :                 SlurTieLayout::layoutTieBack(tieBack, item->system(), ctx);
     121              :             }
     122              :         }
     123        49421 :     };
     124              : 
     125        33503 :     const Fraction stick = item->system()->measures().front()->tick();
     126        33503 :     const size_t tracks = ctx.dom().ntracks();
     127              :     static const SegmentType st { SegmentType::ChordRest };
     128       226442 :     for (track_idx_t track = 0; track < tracks; ++track) {
     129       192939 :         if (!ctx.dom().staff(track2staff(track))->show()) {
     130          663 :             track += VOICES - 1;
     131          663 :             continue;
     132              :         }
     133       563008 :         for (Segment* seg = item->first(st); seg; seg = seg->next(st)) {
     134       370732 :             EngravingItem* element = seg->element(track);
     135       370732 :             if (!element || !element->isChord()) {
     136       322220 :                 continue;
     137              :             }
     138        48512 :             Chord* chord = toChord(element);
     139        48512 :             layoutCrossStaffTies(chord, item, stick, ctx);
     140              : 
     141        49421 :             for (Chord* graceChord : chord->graceNotes()) {
     142          909 :                 layoutCrossStaffTies(graceChord, item, stick, ctx);
     143              :             }
     144              :         }
     145              :     }
     146        33503 : }
     147              : 
     148        36768 : void MeasureLayout::moveToNextMeasure(LayoutContext& ctx)
     149              : {
     150              :     LAYOUT_CALL();
     151        36768 :     LayoutState& state = ctx.mutState();
     152              : 
     153        36768 :     state.setPrevMeasure(state.curMeasure());
     154        36768 :     state.setCurMeasure(state.nextMeasure());
     155        36768 :     if (!state.curMeasure()) {
     156         3822 :         state.setNextMeasure(ctx.conf().isShowVBox() ? ctx.mutDom().first() : ctx.mutDom().firstMeasure());
     157              :     } else {
     158        32946 :         MeasureBase* m = ctx.conf().isShowVBox() ? state.curMeasure()->next() : state.curMeasure()->nextMeasure();
     159        32946 :         state.setNextMeasure(m);
     160              :     }
     161        36768 : }
     162              : 
     163        30347 : void MeasureLayout::checkStaffMoveValidity(Measure* measure, const LayoutContext& ctx)
     164              : {
     165       124438 :     for (const Segment& segment : measure->segments()) {
     166        94091 :         if (!segment.isJustType(SegmentType::ChordRest)) {
     167        30787 :             continue;
     168              :         }
     169              : 
     170       418080 :         for (track_idx_t t = 0; t < ctx.dom().nstaves() * VOICES; ++t) {
     171       354776 :             ChordRest* cr = toChordRest(segment.element(t));
     172       354776 :             if (cr) {
     173              :                 // Check if requested cross-staff is possible
     174        87905 :                 if (cr->staffMove() || cr->storedStaffMove()) {
     175          215 :                     cr->checkStaffMoveValidity();
     176              :                 }
     177              :             }
     178              :         }
     179              :     }
     180        30347 : }
     181              : 
     182        34473 : void MeasureLayout::layoutMeasure(MeasureBase* currentMB, LayoutContext& ctx)
     183              : {
     184        34473 :     if (!currentMB || !currentMB->isMeasure()) {
     185         2437 :         return;
     186              :     }
     187              : 
     188        32036 :     Measure* measure = toMeasure(currentMB);
     189              : 
     190        32036 :     if (!measure->ldata()->needLayout()) {
     191         1593 :         return;
     192              :     }
     193              : 
     194        30443 :     if (ctx.conf().isLinearMode() && (measure->tick() < ctx.state().startTick() || measure->tick() > ctx.state().endTick())) {
     195            0 :         return;
     196              :     }
     197              : 
     198        30443 :     if (ctx.dom().allStavesInvisible()) {
     199           96 :         return;
     200              :     }
     201              : 
     202        30347 :     measure->mutldata()->setNeedLayout(false);
     203              : 
     204              :     // Check if requested cross-staff is possible
     205              :     // This must happen before cmdUpdateNotes
     206        30347 :     checkStaffMoveValidity(measure, ctx);
     207              : 
     208              :     // ---- Modify DOM ----
     209        30347 :     ModifyDom::setCrossMeasure(measure, ctx);
     210        30347 :     ModifyDom::connectTremolo(measure);
     211        30347 :     ModifyDom::cmdUpdateNotes(measure, ctx.dom());
     212        30347 :     ModifyDom::createStems(measure,  ctx);
     213        30347 :     ModifyDom::setTrackForChordGraceNotes(measure, ctx.dom());
     214        30347 :     ModifyDom::sortMeasureSegments(measure, ctx);
     215              :     // --------------------
     216              :     //
     217              :     // calculate accidentals and note lines,
     218              :     // create stem and set stem direction
     219              :     //
     220              : 
     221        30347 :     const DomAccessor& dom = ctx.dom();
     222        30347 :     const LayoutConfiguration& conf = ctx.conf();
     223              : 
     224        74673 :     for (size_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
     225        44326 :         const Staff* staff = dom.staff(staffIdx);
     226              : 
     227        44326 :         track_idx_t startTrack = staffIdx * VOICES;
     228        44326 :         track_idx_t endTrack  = startTrack + VOICES;
     229              : 
     230       180666 :         for (const Segment& segment : measure->segments()) {
     231       136340 :             if (!staff->show() && !segment.isType(SegmentType::TimeSigTypes)) {
     232         1827 :                 continue;
     233              :             }
     234              : 
     235       134513 :             SegmentLayout::layoutMeasureIndependentElements(segment, startTrack, ctx);
     236              : 
     237       134513 :             if (!segment.isJustType(SegmentType::ChordRest)) {
     238        46667 :                 continue;
     239              :             }
     240              : 
     241              :             //! NOTE Maybe it makes sense to group these methods by chord
     242              : 
     243        87846 :             SegmentLayout::setChordMag(staff, segment, startTrack, endTrack, conf);
     244              : 
     245        87846 :             SegmentLayout::layoutChordDrumset(staff, segment, startTrack, endTrack, conf);
     246              : 
     247        87846 :             SegmentLayout::computeChordsUp(segment, startTrack, endTrack, ctx);
     248              : 
     249        87846 :             SegmentLayout::layoutChordsStem(segment, startTrack, endTrack, ctx);
     250              :         }
     251              :     }
     252              : 
     253        30347 :     BeamLayout::createBeams(ctx, measure);
     254              : 
     255              :     /* HACK: The real beam layout is computed at much later stage (you can't do the beams until you know
     256              :      * horizontal spacing). However, horizontal spacing needs to know stems extensions to avoid collision
     257              :      * with stems, and stems extensions depend on beams. Solution: we compute dummy beams here, *before*
     258              :      * horizontal spacing. It is pointless for the beams themselves, but it *does* correctly extend the
     259              :      * stems, thus allowing to compute horizontal spacing correctly. (M.S.) */
     260       124445 :     for (Segment& s : measure->segments()) {
     261        94098 :         if (!s.isChordRestType()) {
     262        30794 :             continue;
     263              :         }
     264       418080 :         for (EngravingItem* item : s.elist()) {
     265       354776 :             if (!item || !item->isChordRest()) {
     266       266871 :                 continue;
     267              :             }
     268        87905 :             if (const Staff* staff = ctx.dom().staff(item->vStaffIdx()); staff && staff->show()) {
     269        87101 :                 BeamLayout::layoutNonCrossBeams(toChordRest(item), ctx);
     270              :             }
     271              :         }
     272              :     }
     273              : 
     274        74673 :     for (staff_idx_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
     275        44326 :         const Staff* staff = ctx.dom().staff(staffIdx);
     276        44326 :         if (!staff->show()) {
     277          667 :             continue;
     278              :         }
     279              : 
     280       178082 :         for (Segment& segment : measure->segments()) {
     281       134423 :             if (segment.isChordRestType()) {
     282        87846 :                 ChordLayout::layoutChords1(ctx, &segment, staffIdx);
     283        87846 :                 RestLayout::resolveVerticalRestConflicts(ctx, &segment, staffIdx);
     284       439230 :                 for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
     285       351384 :                     ChordRest* cr = segment.cr(staffIdx * VOICES + voice);
     286       351384 :                     if (cr) {
     287        89281 :                         for (Lyrics* l : cr->lyrics()) {
     288         2180 :                             if (l) {
     289         2180 :                                 TLayout::layoutLyrics(l, ctx);
     290              :                             }
     291              :                         }
     292              :                     }
     293              :                 }
     294              :             }
     295              :         }
     296              :     }
     297              : 
     298       124445 :     for (Segment& segment : measure->segments()) {
     299        94098 :         if (segment.isBreathType()) {
     300          965 :             for (EngravingItem* e : segment.elist()) {
     301          824 :                 if (e && e->isBreath()) {
     302          168 :                     TLayout::layoutItem(e, ctx);
     303              :                 }
     304              :             }
     305        93957 :         } else if (segment.isChordRestType()) {
     306        63304 :             ChordBracketLayout::layoutSegment(&segment, ctx);
     307        70501 :             for (EngravingItem* e : segment.annotations()) {
     308         7197 :                 if (e->isSymbol() || e->isHarmony() || e->isFretDiagram()) {
     309         2641 :                     TLayout::layoutItem(e, ctx);
     310              :                 }
     311              :             }
     312              :         }
     313              :     }
     314              : 
     315        30347 :     Segment* seg = measure->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0, 1));
     316        30347 :     if (measure->repeatStart()) {
     317          225 :         if (!seg) {
     318          133 :             seg = measure->getSegmentR(SegmentType::StartRepeatBarLine, Fraction(0, 1));
     319              :         }
     320          225 :         barLinesSetSpan(seg, ctx);          // this also creates necessary barlines
     321          567 :         for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
     322          342 :             BarLine* b = toBarLine(seg->element(staffIdx * VOICES));
     323          342 :             if (b) {
     324          342 :                 b->setBarLineType(BarLineType::START_REPEAT);
     325          342 :                 TLayout::layoutBarLine(b, b->mutldata(), ctx);
     326              :             }
     327              :         }
     328        30122 :     } else if (seg) {
     329            4 :         ctx.mutDom().undoRemoveElement(seg);
     330              :     }
     331              : 
     332       124574 :     for (Segment& s : measure->segments()) {
     333        94227 :         if (s.isEndBarLineType()) {
     334        15814 :             continue;
     335              :         }
     336        78413 :         s.createShapes();
     337              :     }
     338              : 
     339        30347 :     measure->computeTicks(); // Must be called *after* Segment::createShapes() because it relies on the
     340              :     // Segment::visible() property, which is determined by Segment::createShapes().
     341              : }
     342              : 
     343        55377 : void MeasureLayout::updateGraceNotes(Measure* measure, LayoutContext& ctx)
     344              : {
     345              :     // Clean everything
     346       265405 :     for (Segment& s : measure->segments()) {
     347      1432488 :         for (track_idx_t track = 0; track < ctx.dom().ntracks(); ++track) {
     348      1222460 :             EngravingItem* e = s.preAppendedItem(track);
     349      1222460 :             if (e && e->isGraceNotesGroup()) {
     350          531 :                 s.clearPreAppended(track);
     351          531 :                 std::set<staff_idx_t> stavesToReShape;
     352         1227 :                 for (Chord* grace : *toGraceNotesGroup(e)) {
     353          696 :                     stavesToReShape.insert(grace->staffIdx());
     354          696 :                     stavesToReShape.insert(grace->vStaffIdx());
     355              :                 }
     356         1054 :                 for (staff_idx_t staffToReshape : stavesToReShape) {
     357          523 :                     s.createShape(staffToReshape);
     358              :                 }
     359          531 :             }
     360              :         }
     361              :     }
     362              : 
     363              :     // Append grace notes to appropriate segment
     364       265405 :     for (Segment& s : measure->segments()) {
     365       210028 :         if (!s.isChordRestType()) {
     366        98188 :             continue;
     367              :         }
     368       740808 :         for (auto el : s.elist()) {
     369       628968 :             if (el && el->isChord() && !toChord(el)->graceNotes().empty()) {
     370          994 :                 ChordLayout::appendGraceNotes(toChord(el));
     371              :             }
     372              :         }
     373              :     }
     374              : 
     375              :     // Layout grace note groups
     376       265405 :     for (Segment& s : measure->segments()) {
     377      1432488 :         for (track_idx_t track = 0; track < ctx.dom().ntracks(); ++track) {
     378      1222460 :             EngravingItem* e = s.preAppendedItem(track);
     379      1222460 :             if (e && e->isGraceNotesGroup()) {
     380         1028 :                 GraceNotesGroup* gng = toGraceNotesGroup(e);
     381         1028 :                 TLayout::layoutGraceNotesGroup(gng, ctx);
     382         1028 :                 gng->addToShape();
     383              :             }
     384              :         }
     385              :     }
     386        55377 : }
     387              : 
     388        36768 : void MeasureLayout::getNextMeasure(LayoutContext& ctx)
     389              : {
     390        36783 :     TRACEFUNC;
     391              :     LAYOUT_CALL();
     392              : 
     393        36768 :     moveToNextMeasure(ctx);
     394              : 
     395        36768 :     updateTicksMeasNumbersAndMMRests(ctx.mutState().curMeasure(), ctx);
     396              : 
     397        36768 :     MeasureBase* mb = ctx.mutState().curMeasure();
     398        36768 :     if (mb && mb->isMeasure()) {
     399        30511 :         toMeasure(mb)->mutldata()->setNeedLayout(true);
     400              :     }
     401        36768 : }
     402              : 
     403        36768 : void MeasureLayout::updateTicksMeasNumbersAndMMRests(MeasureBase* currentMB, LayoutContext& ctx)
     404              : {
     405        36768 :     IF_ASSERT_FAILED(currentMB == ctx.state().curMeasure()) {
     406            0 :         return;
     407              :     }
     408              : 
     409        36768 :     if (!currentMB) {
     410         3822 :         return;
     411              :     }
     412              : 
     413        32946 :     if (!currentMB->isMeasure()) {
     414         2435 :         assert(currentMB->tick() == ctx.state().tick());
     415              : 
     416         2435 :         const LayoutBreak* layoutBreak = currentMB->sectionBreakElement();
     417         2435 :         if (layoutBreak && layoutBreak->startWithMeasureOne()) {
     418           18 :             ctx.mutState().setMeasureNumber(0);
     419              :         }
     420              : 
     421         2435 :         return;
     422              :     }
     423              : 
     424        30511 :     Measure* measure = toMeasure(currentMB);
     425              : 
     426        30511 :     int measureNumber = adjustMeasureNumber(measure, ctx.state().measureNumber());
     427              : 
     428        30511 :     ctx.mutState().setMeasureNumber(measureNumber);
     429              : 
     430        30511 :     MMRestLayout::createMultiMeasureRestsIfNeed(measure, ctx);
     431              : 
     432        30511 :     currentMB = ctx.mutState().curMeasure();
     433        30511 :     measure = toMeasure(currentMB);
     434              : 
     435        30511 :     measure->moveTicks(ctx.state().tick() - measure->tick());
     436              : 
     437        30511 :     ctx.mutState().setTick(ctx.state().tick() + measure->ticks());
     438              : }
     439              : 
     440              : //---------------------------------------------------------
     441              : //   adjustMeasureNumber
     442              : //---------------------------------------------------------
     443              : 
     444        30964 : int MeasureLayout::adjustMeasureNumber(Measure* m, int measureNumber)
     445              : {
     446        30964 :     measureNumber += m->measureNumberOffset();
     447        30964 :     m->setMeasureNumber(measureNumber);
     448        30964 :     if (!m->excludeFromNumbering()) {
     449        30930 :         ++measureNumber;
     450              :     }
     451              : 
     452        30964 :     const LayoutBreak* layoutBreak = m->sectionBreakElement();
     453        30964 :     if (layoutBreak && layoutBreak->startWithMeasureOne()) {
     454           51 :         measureNumber = 0;
     455              :     }
     456              : 
     457        30964 :     return measureNumber;
     458              : }
     459              : 
     460              : /****************************************************************
     461              :  * computePreSpacingItems
     462              :  * Computes information that is needed before horizontal spacing.
     463              :  * Caution: assumes that the system is known! (which is why we
     464              :  * cannot compute this stuff in LayoutMeasure::getNextMeasure().)
     465              :  * **************************************************************/
     466        32006 : void MeasureLayout::computePreSpacingItems(Measure* m, LayoutContext& ctx)
     467              : {
     468              :     // Compute chord properties
     469        32006 :     bool isFirstChordInMeasure = true;
     470        32006 :     ChordLayout::clearLineAttachPoints(m);
     471       132873 :     for (Segment& seg : m->segments()) {
     472       100867 :         if (!seg.isChordRestType()) {
     473        33973 :             continue;
     474              :         }
     475       445370 :         for (EngravingItem* e : seg.elist()) {
     476       378476 :             if (!e || !e->isChord()) {
     477       326659 :                 continue;
     478              :             }
     479        51817 :             Chord* chord = toChord(e);
     480        51817 :             Staff* staff = chord->staff();
     481        51817 :             if (staff && !staff->show()) {
     482          136 :                 continue;
     483              :             }
     484              : 
     485        51681 :             ChordLayout::updateLineAttachPoints(chord, isFirstChordInMeasure, ctx);
     486        52590 :             for (Chord* gn : chord->graceNotes()) {
     487          909 :                 ChordLayout::updateLineAttachPoints(gn, false, ctx);
     488              :             }
     489        51681 :             if (chord->arpeggio()) {
     490          252 :                 ArpeggioLayout::clearAccidentals(chord->arpeggio(), ctx);
     491              :             }
     492              : 
     493        51681 :             ChordLayout::layoutArticulations(chord, ctx);
     494        51681 :             ChordLayout::checkStartEndSlurs(chord, ctx);
     495        51681 :             ChordLayout::layoutArticulations2(chord, ctx);
     496        51681 :             chord->computeKerningExceptions();
     497              :         }
     498              : 
     499        74197 :         for (EngravingItem* annotation : seg.annotations()) {
     500         7303 :             if (annotation->isFermata()) {
     501          275 :                 TLayout::layoutItem(annotation, ctx);
     502              :             }
     503              :         }
     504              : 
     505        66894 :         ChordBracketLayout::layoutSegment(&seg, ctx);
     506        66894 :         seg.createShapes();
     507        66894 :         isFirstChordInMeasure = false;
     508              :     }
     509        32006 : }
     510              : 
     511        30273 : void MeasureLayout::layoutStaffLines(Measure* m, LayoutContext& ctx)
     512              : {
     513        30273 :     int staffIdx = 0;
     514        74463 :     for (const MStaff* ms : m->mstaves()) {
     515        44190 :         if (m->isCutawayClef(staffIdx) && (ctx.dom().staff(staffIdx)->cutaway() || !m->visible(staffIdx))) {
     516              :             // draw short staff lines for a courtesy clef on a hidden measure
     517            0 :             Segment* clefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
     518            0 :             double staffMag = ctx.dom().staff(staffIdx)->staffMag(m->tick());
     519              :             double partialWidth = clefSeg
     520            0 :                                   ? m->width() - clefSeg->x() + clefSeg->minLeft() + ctx.conf().styleAbsolute(Sid::clefLeftMargin)
     521            0 :                                   * staffMag
     522            0 :                                   : 0.0;
     523            0 :             layoutPartialWidth(ms->lines(), ctx, m->width(), partialWidth / (m->spatium() * staffMag), true);
     524              :         } else {
     525              :             // normal staff lines
     526        44190 :             TLayout::layoutStaffLines(ms->lines(), ctx);
     527              :         }
     528        44190 :         staffIdx += 1;
     529              :     }
     530        30273 : }
     531              : 
     532        31790 : void MeasureLayout::layoutPlayCountText(Measure* m, LayoutContext& ctx)
     533              : {
     534        31790 :     if (!m->repeatEnd()) {
     535        31399 :         return;
     536              :     }
     537              : 
     538          391 :     Score* score = m->score();
     539          391 :     const std::vector<MStaff*>& measureStaves = m->mstaves();
     540              : 
     541          903 :     for (staff_idx_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     542          512 :         if (staffIdx >= measureStaves.size()) {
     543            0 :             break;
     544              :         }
     545          512 :         track_idx_t track = staff2track(staffIdx);
     546              : 
     547          512 :         Segment* endBarSeg = m->last(SegmentType::BarLineTypes);
     548              :         PlayCountText* playCount
     549          512 :             = endBarSeg ? toPlayCountText(endBarSeg->findAnnotation(ElementType::PLAY_COUNT_TEXT, track, track)) : nullptr;
     550          512 :         if (!playCount) {
     551          506 :             continue;
     552              :         }
     553              : 
     554            6 :         String text;
     555            6 :         const int repeatCount = m->repeatCount();
     556           12 :         String defaultText = TConv::translatedUserName(ctx.conf().styleV(Sid::repeatPlayCountPreset).value<RepeatPlayCountPreset>()).arg(
     557            6 :             repeatCount);
     558              : 
     559            6 :         switch (playCount->playCountTextSetting()) {
     560            6 :         case AutoCustomHide::AUTO:
     561            6 :             text = defaultText;
     562            6 :             break;
     563            0 :         case AutoCustomHide::CUSTOM:
     564            0 :             text = playCount->playCountCustomText();
     565            0 :             if (text.empty()) {
     566            0 :                 text = defaultText;
     567              :             }
     568            0 :             break;
     569            0 :         case AutoCustomHide::HIDE:
     570            0 :             playCount->mutldata()->setIsSkipDraw(true);
     571            0 :             break;
     572              :         }
     573              : 
     574            6 :         if (!playCount->cursor()->editing()) {
     575            6 :             playCount->setXmlText(text);
     576              :         }
     577            6 :     }
     578              : }
     579              : 
     580        31790 : void MeasureLayout::layoutMeasureNumber(Measure* m, LayoutContext& ctx)
     581              : {
     582        31790 :     MeasureNumberPlacement placementMode = ctx.conf().styleV(Sid::measureNumberPlacementMode).value<MeasureNumberPlacement>();
     583              : 
     584        31790 :     String stringNum = String::number(m->measureNumber() + 1);
     585              : 
     586        31790 :     Score* score = m->score();
     587              : 
     588        31790 :     const std::vector<MStaff*>& measureStaves = m->mstaves();
     589              : 
     590        78630 :     for (staff_idx_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     591        46840 :         if (staffIdx >= measureStaves.size()) {
     592            0 :             break;
     593              :         }
     594              : 
     595        46840 :         if (m->showMeasureNumberOnStaff(staffIdx)) {
     596         3851 :             MeasureNumber* measureNumber = measureStaves[staffIdx]->measureNumber();
     597         3851 :             if (!measureNumber) {
     598         2335 :                 measureNumber = new MeasureNumber(m);
     599         2335 :                 measureNumber->setTrack(staff2track(staffIdx));
     600         2335 :                 measureNumber->setGenerated(true);
     601         2335 :                 m->add(measureNumber);
     602              :             }
     603              : 
     604         3851 :             measureNumber->setXmlText(stringNum);
     605         3851 :             measureNumber->setSystemFlag(placementMode != MeasureNumberPlacement::ON_ALL_STAVES);
     606         3851 :             TLayout::layoutMeasureNumber(measureNumber, measureNumber->mutldata(), ctx);
     607              :         }
     608              :     }
     609        31790 : }
     610              : 
     611        28569 : MeasureLayout::MeasureStartEndPos MeasureLayout::getMeasureStartEndPos(const Measure* measure, const Segment* firstCrSeg,
     612              :                                                                        const staff_idx_t staffIdx, const bool needsHeaderException,
     613              :                                                                        const bool modernMMRest,
     614              :                                                                        const LayoutContext& ctx)
     615              : {
     616        28569 :     if (!measure || !firstCrSeg) {
     617            0 :         return MeasureStartEndPos(0.0, 0.0);
     618              :     }
     619              : 
     620              :     Segment* s1;
     621        31447 :     for (s1 = firstCrSeg->prevActive(); s1 && s1->allElementsInvisible(); s1 = s1->prevActive()) {
     622              :     }
     623              :     Segment* s2;
     624              : 
     625        31890 :     for (s2 = firstCrSeg->nextActive(); s2; s2 = s2->nextActive()) {
     626        31857 :         if (modernMMRest && !s2->isChordRestType() && !s2->isBreathType() && s2->element(staffIdx * VOICES)) {
     627          148 :             break;
     628              :         }
     629              : 
     630        63418 :         if (!modernMMRest
     631        31704 :             && (s2->isClefRepeatAnnounceType() || (s2->isTimeSigRepeatAnnounceType() && !s2->hasTimeSigAboveStaves())
     632        63413 :                 || s2->isKeySigRepeatAnnounceType() || s2->isEndBarLineType()) && s2->element(staffIdx * VOICES)) {
     633        28388 :             break;
     634              :         }
     635              :     }
     636              : 
     637        28569 :     double x1 = 0.0;
     638        40436 :     while (s1) {
     639        11879 :         if (!s1->hasTimeSigAboveStaves() && !s1->allElementsInvisible()) {
     640        10509 :             x1 = std::max(x1, s1->x() + s1->minRight());
     641        10509 :             if (s1->isCourtesySegment()) {
     642           12 :                 break;
     643              :             }
     644              :         }
     645        11867 :         s1 = s1->prevActive();
     646              :     }
     647              : 
     648        28569 :     double x2 = s2 ? s2->x() - s2->minLeft() : measure->width();
     649              : 
     650        33650 :     bool headerException = measure->header() && firstCrSeg->prev() && !firstCrSeg->prev()->isStartRepeatBarLineType()
     651        33650 :                            && needsHeaderException;
     652        28569 :     if (headerException) { //needs this exception on header bar
     653              :         // Set x1 to the imaginary barline located the minimum barline->note distance to the left of the rest's segment
     654           86 :         x1 = firstCrSeg->x() - ctx.conf().styleAbsolute(Sid::barNoteDistance);
     655              :     }
     656              : 
     657        28569 :     return MeasureStartEndPos(x1, x2);
     658              : }
     659              : 
     660              : //-----------------------------------------------------------------------------
     661              : //  layoutMeasureElements()
     662              : //  lays out all the element of a measure
     663              : //  LEGACY: this method used to be called stretchMeasure() and was used to
     664              : //  distribute the remaining space at the end of a system. That task is now
     665              : //  performed elsewhere and only the layout tasks are kept.
     666              : //-----------------------------------------------------------------------------
     667              : 
     668        30415 : void MeasureLayout::layoutMeasureElements(Measure* m, LayoutContext& ctx)
     669              : {
     670              :     //---------------------------------------------------
     671              :     //    layout individual elements
     672              :     //---------------------------------------------------
     673              : 
     674       147477 :     for (Segment& s : m->segments()) {
     675       117062 :         if (!s.enabled()) {
     676          980 :             continue;
     677              :         }
     678              : 
     679              :         // After the rest of the spacing is calculated we position grace-notes-after.
     680       116082 :         ChordLayout::repositionGraceNotesAfter(&s, ctx.dom().ntracks());
     681              : 
     682       791750 :         for (EngravingItem* e : s.elist()) {
     683       675668 :             if (!e) {
     684       508136 :                 continue;
     685              :             }
     686       167532 :             staff_idx_t staffIdx = e->staffIdx();
     687       167532 :             bool modernMMRest = e->isMMRest() && !toMMRest(e)->isOldStyle();
     688       167532 :             if ((e->isRest() && toRest(e)->isFullMeasureRest()) || e->isMMRest() || e->isMeasureRepeat()) {
     689              :                 //
     690              :                 // element has to be centered in free space
     691              :                 //    x1 - left measure position of free space
     692              :                 //    x2 - right measure position of free space
     693              : 
     694        28569 :                 const MeasureStartEndPos measureStartEnd = getMeasureStartEndPos(m, &s, staffIdx, e->isMMRest(), modernMMRest, ctx);
     695              : 
     696        28569 :                 const double x1 = measureStartEnd.x1;
     697        28569 :                 const double x2 = measureStartEnd.x2;
     698              : 
     699        28569 :                 if (e->isMMRest()) {
     700          181 :                     MMRest* mmrest = toMMRest(e);
     701              :                     // center multimeasure rest
     702          181 :                     double d = ctx.conf().styleAbsolute(Sid::multiMeasureRestMargin);
     703          181 :                     double w = x2 - x1 - 2 * d;
     704          181 :                     MMRest::LayoutData* mmrestLD = mmrest->mutldata();
     705          181 :                     mmrestLD->restWidth = w;
     706          181 :                     TLayout::layoutMMRest(mmrest, mmrest->mutldata(), ctx);
     707          181 :                     mmrestLD->setPosX(x1 - s.x() + d);
     708        28388 :                 } else if (e->isMeasureRepeat() && !(toMeasureRepeat(e)->numMeasures() % 2)) {
     709              :                     // two- or four-measure repeat, center on following barline
     710           89 :                     double measureWidth = x2 - s.x() + .5 * (m->styleP(Sid::barWidth));
     711           89 :                     e->mutldata()->setPosX(measureWidth - .5 * e->width());
     712           89 :                     if (toMeasureRepeat(e)->numMeasures() == 4 && ctx.conf().styleB(Sid::fourMeasureRepeatShowExtenders)) {
     713            0 :                         TLayout::layoutMeasureRepeatExtender(toMeasureRepeat(e), toMeasureRepeat(e)->mutldata(), ctx);
     714              :                     }
     715              :                 } else {
     716              :                     // full measure rest or one-measure repeat, center within this measure
     717        28299 :                     TLayout::layoutItem(e, ctx);
     718        28299 :                     Shape sh = e->ldata()->shape();
     719        28299 :                     auto shEL = sh.find_first(ElementType::REST);
     720              :                     //! HACK Previously, bbox of rest was used here
     721              :                     //! Now we are using a shape, and in the shape we need to find the part related to rest
     722              :                     //! But in some cases, the information about what the ShapeElement belongs to will disappear at the moment (item is null),
     723              :                     //! in this case, let's just take the first element, it currently corresponds to the rest
     724        28299 :                     if (!shEL) {
     725          857 :                         shEL = sh.get_first();
     726              :                     }
     727        28299 :                     if (shEL) {
     728        27580 :                         e->mutldata()->setPosX((x2 - x1 - shEL->width()) * .5 + x1 - s.x() - shEL->x());
     729              :                     }
     730        28299 :                 }
     731        28569 :                 s.createShape(staffIdx);            // DEBUG
     732       138963 :             } else if (e->isRest()) {
     733        11159 :                 e->mutldata()->setPosX(0);
     734       127804 :             } else if (e->isChord()) {
     735        48273 :                 Chord* c = toChord(e);
     736        48273 :                 if (c->tremoloSingleChord()) {
     737          268 :                     TremoloLayout::layout(c->tremoloSingleChord(), ctx);
     738              :                 }
     739              : 
     740        48273 :                 if (c->tremoloTwoChord()) {
     741          220 :                     TremoloTwoChord* tr = c->tremoloTwoChord();
     742          220 :                     Chord* c1 = tr->chord1();
     743          220 :                     Chord* c2 = tr->chord2();
     744          220 :                     if (c1 && !c1->staffMove() && c2 && !c2->staffMove()) {
     745          220 :                         TremoloLayout::layout(tr, ctx);
     746              :                     }
     747              :                 }
     748              : 
     749        49179 :                 for (Chord* g : c->graceNotes()) {
     750          906 :                     if (g->tremoloSingleChord()) {
     751            2 :                         TremoloLayout::layout(g->tremoloSingleChord(), ctx);
     752              :                     }
     753              : 
     754          906 :                     if (g->tremoloTwoChord()) {
     755            0 :                         TremoloTwoChord* tr = g->tremoloTwoChord();
     756            0 :                         Chord* gc1 = tr->chord1();
     757            0 :                         Chord* gc2 = tr->chord2();
     758            0 :                         if (gc1 && !gc1->staffMove() && gc2 && !gc2->staffMove()) {
     759            0 :                             TremoloLayout::layout(tr, ctx);
     760              :                         }
     761              :                     }
     762              :                 }
     763        79531 :             } else if (e->isBarLine()) {
     764        50442 :                 e->mutldata()->setPosY(0.0);
     765              :                 // for end barlines, x position was set in createEndBarLines
     766        50442 :                 if (s.segmentType() != SegmentType::EndBarLine) {
     767         6174 :                     e->mutldata()->setPosX(0.0);
     768              :                 }
     769              :             }
     770              :         }
     771              :     }
     772        30415 : }
     773              : 
     774          225 : void MeasureLayout::barLinesSetSpan(Segment* seg, LayoutContext& ctx)
     775              : {
     776          225 :     int track = 0;
     777          567 :     for (Staff* staff : ctx.dom().staves()) {
     778          342 :         BarLine* bl = toBarLine(seg->element(track));      // get existing bar line for this staff, if any
     779          342 :         if (bl) {
     780          133 :             if (bl->generated()) {
     781          122 :                 bl->setSpanStaff(staff->barLineSpan());
     782          122 :                 bl->setSpanFrom(staff->barLineFrom());
     783          122 :                 bl->setSpanTo(staff->barLineTo());
     784              :             }
     785              :         } else {
     786          209 :             bl = Factory::createBarLine(seg);
     787          209 :             bl->setTrack(track);
     788          209 :             bl->setGenerated(true);
     789          209 :             bl->setSpanStaff(staff->barLineSpan());
     790          209 :             bl->setSpanFrom(staff->barLineFrom());
     791          209 :             bl->setSpanTo(staff->barLineTo());
     792          209 :             TLayout::layoutBarLine(bl, bl->mutldata(), ctx);
     793          209 :             ctx.mutDom().addElement(bl);
     794              :         }
     795          342 :         track += VOICES;
     796              :     }
     797          225 : }
     798              : 
     799              : //---------------------------------------------------------
     800              : //   createEndBarLines
     801              : //    actually creates or modifies barlines
     802              : //    return the width change for measure
     803              : //---------------------------------------------------------
     804              : 
     805        62409 : void MeasureLayout::createEndBarLines(Measure* m, bool isLastMeasureInSystem, LayoutContext& ctx)
     806              : {
     807        62409 :     const size_t nstaves = ctx.dom().nstaves();
     808        62409 :     Segment* barlineSeg = m->findSegmentR(SegmentType::EndBarLine, m->ticks());
     809        62409 :     const Measure* nextMeasure = m->nextMeasure();
     810        62409 :     double barlineWidth = 0.0;
     811        62409 :     bool sectionBreakHideCourtesy = false;
     812        62409 :     if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
     813          110 :         sectionBreakHideCourtesy = !sectionBreakElement->showCourtesy();
     814              :     }
     815              : 
     816        62409 :     m->setHasCourtesyKeySig(false);
     817              :     //  Set flag "hasCourtesyKeySig" if this measure needs a courtesy key sig.
     818              :     //  This flag is later used to set a double end bar line and to actually
     819              :     //  create the courtesy key sig.
     820              : 
     821        62409 :     bool hasKeySig = false;
     822        62409 :     bool hasTimeSig = false;
     823        62409 :     bool hasCourtesyTimeSig = false;
     824        62409 :     if (nextMeasure && !sectionBreakHideCourtesy) {
     825              :         //  Don't change barlines at the end of a section break,
     826              :         //  and don't create courtesy key/time signatures.
     827        31327 :         const bool showCourtesyKeySig = (isLastMeasureInSystem && ctx.conf().styleB(Sid::genCourtesyKeysig))
     828        85858 :                                         || (m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps));
     829              : 
     830        54531 :         Fraction tick = m->endTick();
     831       132190 :         for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
     832        78376 :             const Staff* staff     = ctx.dom().staff(staffIdx);
     833        78376 :             const KeySigEvent key1 = staff->keySigEvent(tick - Fraction::eps());
     834        78376 :             const KeySigEvent key2 = staff->keySigEvent(tick);
     835        78376 :             if (key1 == key2) {
     836        77659 :                 continue;
     837              :             }
     838              :             // locate a key sig. in next measure and, if found,
     839              :             // check if it has court. sig turned off
     840          717 :             Segment* keySigSeg = nextMeasure->findSegment(SegmentType::KeySig, tick);
     841          717 :             if (keySigSeg) {
     842          717 :                 hasKeySig = true;
     843          717 :                 KeySig* keySig = toKeySig(keySigSeg->element(staffIdx * VOICES));
     844          717 :                 if (keySig && !keySig->showCourtesy()) {
     845            0 :                     continue;
     846              :                 }
     847              :             }
     848          717 :             if (showCourtesyKeySig) {
     849          456 :                 m->setHasCourtesyKeySig(true);
     850              :             }
     851          717 :             break;
     852       156752 :         }
     853              : 
     854        31327 :         bool showCourtesyTimeSig = (isLastMeasureInSystem && ctx.conf().styleB(Sid::genCourtesyTimesig))
     855        85858 :                                    || (m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps));
     856              : 
     857        54531 :         Segment* timeSigSeg = nextMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1));
     858        54531 :         if (timeSigSeg) {
     859          657 :             for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
     860          602 :                 TimeSig* timeSig = toTimeSig(timeSigSeg->element(track));
     861          602 :                 if (!timeSig) {
     862           83 :                     continue;
     863              :                 }
     864          519 :                 hasTimeSig = true;
     865          519 :                 if (timeSig->showCourtesySig() && showCourtesyTimeSig) {
     866          339 :                     hasCourtesyTimeSig = true;
     867              :                 }
     868          519 :                 break;
     869              :             }
     870              :         }
     871              :     }
     872              : 
     873        54639 :     bool nextMeasRepeat = nextMeasure && nextMeasure->repeatStart() && !m->repeatEnd() && !isLastMeasureInSystem
     874       117048 :                           && m->next() == nextMeasure;
     875              : 
     876        62409 :     bool barlineBeforeRepeatSigs = ctx.conf().styleB(Sid::barlineBeforeSigChange) && (hasTimeSig || hasKeySig);
     877              : 
     878        62409 :     if (nextMeasRepeat && !barlineBeforeRepeatSigs) {
     879              :         // we may skip barline at end of a measure immediately before a start repeat:
     880              :         // next measure is repeat start, this measure is not a repeat end,
     881              :         // this is not last measure of system, no intervening frame
     882           97 :         if (!barlineSeg) {
     883            0 :             return;
     884              :         }
     885           97 :         barlineSeg->setEnabled(false);
     886              :     } else {
     887        62312 :         BarLineType blType = nextMeasure ? BarLineType::NORMAL : BarLineType::END;
     888        62312 :         if (!barlineSeg) {
     889        14565 :             barlineSeg = m->getSegmentR(SegmentType::EndBarLine, m->ticks());
     890              :         }
     891        62312 :         barlineSeg->setEnabled(true);
     892              : 
     893        62312 :         const bool isRepeatSigBarline = ctx.conf().styleB(Sid::barlineBeforeSigChange) && nextMeasRepeat;
     894              : 
     895        62312 :         const int keySigBarlineMode = ctx.conf().styleI(Sid::keySigCourtesyBarlineMode);
     896        62312 :         const bool beforeKSCourtesy = keySigBarlineMode == int(CourtesyBarlineMode::DOUBLE_BEFORE_COURTESY) && m->hasCourtesyKeySig();
     897        62312 :         const bool alwaysDoubleKS = keySigBarlineMode == int(CourtesyBarlineMode::ALWAYS_DOUBLE) && hasKeySig;
     898        62312 :         const bool beforeRepeatKS = isRepeatSigBarline && hasKeySig && ctx.conf().styleB(Sid::doubleBarlineBeforeKeySig);
     899        62312 :         if (beforeKSCourtesy || alwaysDoubleKS || beforeRepeatKS) {
     900          456 :             blType = BarLineType::DOUBLE;
     901              :         }
     902              : 
     903        62312 :         const int timeSigBarlineMode = ctx.conf().styleI(Sid::timeSigCourtesyBarlineMode);
     904        62312 :         const bool beforeTSCourtesy = timeSigBarlineMode == int(CourtesyBarlineMode::DOUBLE_BEFORE_COURTESY) && hasCourtesyTimeSig;
     905        62312 :         const bool alwaysDoubleTS = timeSigBarlineMode == int(CourtesyBarlineMode::ALWAYS_DOUBLE) && hasTimeSig;
     906        62312 :         const bool beforeRepeatTS = isRepeatSigBarline && hasTimeSig && ctx.conf().styleB(Sid::doubleBarlineBeforeTimeSig);
     907              : 
     908        62312 :         if (beforeTSCourtesy || alwaysDoubleTS || beforeRepeatTS) {
     909            0 :             blType = BarLineType::DOUBLE;
     910              :         }
     911              : 
     912        62312 :         bool force = false;
     913        62312 :         if (m->repeatEnd()) {
     914          781 :             blType = BarLineType::END_REPEAT;
     915          781 :             force = true;
     916              :         }
     917              : 
     918       153317 :         for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
     919        91005 :             track_idx_t track = staffIdx * VOICES;
     920        91005 :             BarLine* barLine  = toBarLine(barlineSeg->element(track));
     921        91005 :             const Staff* staff = ctx.dom().staff(staffIdx);
     922        91005 :             if (!barLine) {
     923        21673 :                 barLine = Factory::createBarLine(barlineSeg);
     924        21673 :                 barLine->setTrack(track);
     925        21673 :                 barLine->setGenerated(true);
     926        21673 :                 barLine->setSpanStaff(staff->barLineSpan());
     927        21673 :                 barLine->setSpanFrom(staff->barLineFrom());
     928        21673 :                 barLine->setSpanTo(staff->barLineTo());
     929        21673 :                 barLine->setBarLineType(blType);
     930        21673 :                 ctx.mutDom().addElement(barLine);
     931              :             } else {
     932              :                 // do not change bar line type if bar line is user modified
     933              :                 // and its not a repeat start/end barline (forced)
     934              : 
     935        69332 :                 if (barLine->generated()) {
     936        61276 :                     barLine->setSpanStaff(staff->barLineSpan());
     937        61276 :                     barLine->setSpanFrom(staff->barLineFrom());
     938        61276 :                     barLine->setSpanTo(staff->barLineTo());
     939        61276 :                     barLine->setBarLineType(blType);
     940         8056 :                 } else if (barLine->barLineType() != blType && force) {
     941           43 :                     barLine->setBarLineType(blType);
     942           43 :                     barLine->setGenerated(true);
     943              :                 }
     944              :             }
     945              : 
     946        91005 :             TLayout::layoutBarLine(barLine, barLine->mutldata(), ctx);
     947        91005 :             barlineWidth = std::max(barlineWidth, barLine->width());
     948              :         }
     949              :         // right align within segment
     950       153317 :         for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
     951        91005 :             track_idx_t track = staffIdx * VOICES;
     952        91005 :             BarLine* barLine = toBarLine(barlineSeg->element(track));
     953        91005 :             if (!barLine) {
     954            0 :                 continue;
     955              :             }
     956        91005 :             barLine->mutldata()->moveX(barlineWidth - barLine->width());
     957              :         }
     958        62312 :         barlineSeg->createShapes();
     959              :     }
     960              : 
     961        62409 :     setClefSegVisibility(m, isLastMeasureInSystem, ctx);
     962              : }
     963              : 
     964        62409 : void MeasureLayout::setClefSegVisibility(Measure* m, bool isLastMeasureInSystem, LayoutContext& ctx)
     965              : {
     966        62409 :     const size_t nstaves  = ctx.dom().nstaves();
     967        62409 :     bool sectionBreakHideCourtesy = false;
     968        62409 :     if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
     969          110 :         sectionBreakHideCourtesy = !sectionBreakElement->showCourtesy();
     970              :     }
     971        62409 :     const Measure* nextMeasure  = m->nextMeasure();
     972              : 
     973        62409 :     Segment* clefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
     974        62409 :     if (!clefSeg && nextMeasure) {
     975        54168 :         clefSeg = nextMeasure->findSegmentR(SegmentType::Clef, Fraction(0, 1));
     976              :     }
     977              : 
     978        62409 :     if (!clefSeg) {
     979        61928 :         return;
     980              :     }
     981              : 
     982          481 :     bool visibleClef = false;
     983          481 :     bool clefFound = false;
     984         1156 :     for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
     985          675 :         if (!ctx.dom().staff(staffIdx)->show()) {
     986            8 :             continue;
     987              :         }
     988              : 
     989          667 :         const track_idx_t track = staffIdx * VOICES;
     990          667 :         Clef* clef = toClef(clefSeg->element(track));
     991          667 :         if (!clef) {
     992          162 :             continue;
     993              :         }
     994              : 
     995          505 :         clefFound = true;
     996              : 
     997          505 :         const bool showCourtesy = ctx.conf().styleB(Sid::genCourtesyClef) && clef->showCourtesy();             // normally show a courtesy clef
     998              :         // check if the measure is the last measure of the system or the last measure before a frame
     999          505 :         const bool lastMeasure = isLastMeasureInSystem || (nextMeasure ? !(m->next() == nextMeasure) : true);
    1000          505 :         if (!nextMeasure || sectionBreakHideCourtesy || (lastMeasure && !showCourtesy)) {
    1001              :             // hide the courtesy clef in the final measure of a section, or if the measure is the final measure of a system
    1002              :             // and the score style or the clef style is set to "not show courtesy clef",
    1003              :             // or if the clef is at the end of the very last measure of the score
    1004           57 :             clef->clear();
    1005           57 :             clefSeg->createShape(staffIdx);
    1006              :         } else {
    1007          448 :             TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
    1008          448 :             clefSeg->createShape(staffIdx);
    1009          448 :             visibleClef = true;
    1010              :         }
    1011              :     }
    1012              : 
    1013          481 :     if (visibleClef) {                       // there is at least one visible clef in the clef segment
    1014          442 :         clefSeg->setVisible(true);
    1015           39 :     } else if (!visibleClef && clefFound) {  // all (courtesy) clefs in the clef segment are not visible
    1016           39 :         clefSeg->setVisible(false);
    1017              :     } else { // should never happen
    1018            0 :         LOGD("Clef Segment without Clef elements at tick %d/%d", clefSeg->tick().numerator(), clefSeg->tick().denominator());
    1019            0 :         clefSeg->setVisible(false);
    1020            0 :         return;
    1021              :     }
    1022              : }
    1023              : 
    1024        32077 : void MeasureLayout::setCourtesyTimeSig(Measure* m, const Fraction& refSigTick, const Fraction& courtesySigTick,
    1025              :                                        const SegmentType courtesySegType, LayoutContext& ctx)
    1026              : {
    1027              :     // Find original element
    1028        32077 :     const size_t nstaves = ctx.dom().nstaves();
    1029        32077 :     const Fraction courtesySigRTick = courtesySigTick - m->tick();
    1030        32077 :     const Measure* prevMeasure = m->prevMeasureMM();
    1031              : 
    1032        32077 :     const bool isTrailer = courtesySegType == SegmentType::TimeSigAnnounce;
    1033        32077 :     const bool isContinuationCourtesy = courtesySegType == SegmentType::TimeSigStartRepeatAnnounce;
    1034              : 
    1035              :     const Segment* prevCourtesySegment
    1036        32077 :         = prevMeasure ? prevMeasure->findSegmentR(SegmentType::TimeSigRepeatAnnounce, prevMeasure->ticks()) : nullptr;
    1037              : 
    1038              :     // Cont. courtesies - check for sig at the start of the measure OR end of previous measure if changesBeforeBarline... is on
    1039          585 :     const bool checkPrevMeasure = isContinuationCourtesy && prevMeasure
    1040        32940 :                                   && ((prevMeasure->repeatEnd() && ctx.conf().styleB(Sid::changesBeforeBarlineRepeats))
    1041          278 :                                       || (prevMeasure->repeatJump()
    1042          278 :                                           && ctx.conf().styleB(Sid::changesBeforeBarlineOtherJumps)));
    1043        32077 :     const Segment* tsSegAtCourtesyTick = m->findSegmentR(SegmentType::TimeSig, courtesySigRTick);
    1044        32659 :     tsSegAtCourtesyTick = !tsSegAtCourtesyTick && checkPrevMeasure ? prevMeasure->findSegmentR(SegmentType::TimeSig,
    1045              :                                                                                                courtesySigTick
    1046          582 :                                                                                                - prevMeasure->tick()) : tsSegAtCourtesyTick;
    1047        32077 :     const bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyTimeSig();
    1048              : 
    1049        32077 :     Segment* courtesySigSeg = m->findSegmentR(courtesySegType, courtesySigRTick);
    1050        78348 :     for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
    1051        46271 :         const Staff* staff = ctx.dom().staff(track2staff(track));
    1052        46271 :         const TimeSig* actualTimeSig = staff->timeSig(refSigTick);
    1053        46271 :         const TimeSig* curTimeSig = staff->timeSig(courtesySigTick - Fraction::eps());
    1054        46271 :         if (!actualTimeSig || !curTimeSig) {
    1055          771 :             continue;
    1056              :         }
    1057              : 
    1058              :         // Show repeat courtesy if the sigs are different
    1059              :         // Show continuation courtesy if there's a repeat courtesy before it
    1060              :         // Show trailer courtesy only when there's a time sig element in the next bar
    1061        45500 :         const bool sigsDifferent = actualTimeSig->sig() != curTimeSig->sig();
    1062        90166 :         const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
    1063        44666 :             track) : isTrailer ? actualTimeSig->tick() == m->endTick() : sigsDifferent;
    1064              :         // If there is a real key sig at this tick (in this bar or the previous), don't create a courtesy
    1065        45500 :         const bool hasSigAtTick = tsSegAtCourtesyTick && tsSegAtCourtesyTick->enabled() && tsSegAtCourtesyTick->element(track);
    1066              :         // Only show courtesy if its real signature has courtesies enabled
    1067        45500 :         const bool actualShowCourtesy = actualTimeSig && actualTimeSig->showCourtesySig();
    1068        45500 :         const bool show = actualShowCourtesy && needsCourtesy && !hasSigAtTick && ctx.conf().styleB(Sid::genCourtesyTimesig);
    1069              : 
    1070        45500 :         if (!courtesySigSeg) {
    1071        45159 :             if (!show) {
    1072        44985 :                 continue;
    1073              :             }
    1074              : 
    1075              :             // Create a segment if one doesn't already exist
    1076          174 :             courtesySigSeg  = Factory::createSegment(m, courtesySegType, courtesySigRTick);
    1077          174 :             m->add(courtesySigSeg);
    1078          174 :             m->setTrailer(m->trailer() || isTrailer);
    1079              :         }
    1080          515 :         if (!isContinuationCourtesy) {
    1081          500 :             m->setHasCourtesyTimeSig(true);
    1082              :         }
    1083          515 :         courtesySigSeg->setTrailer(isTrailer);
    1084          515 :         courtesySigSeg->setEnabled(true);
    1085              : 
    1086              :         // Find courtesy element or create if it doesn't exist
    1087          515 :         TimeSig* courtesyTimeSig = nullptr;
    1088          515 :         EngravingItem* timeSigElem = courtesySigSeg->element(track);
    1089          515 :         if (timeSigElem && timeSigElem->isTimeSig()) {
    1090          250 :             courtesyTimeSig = toTimeSig(timeSigElem);
    1091              :         }
    1092              : 
    1093              :         // this time sig shouldn't be shown, remove from segment
    1094          515 :         if (!show) {
    1095           28 :             if (courtesyTimeSig) {
    1096            4 :                 courtesySigSeg->remove(courtesyTimeSig);
    1097              :             }
    1098           28 :             continue;
    1099              :         }
    1100              : 
    1101          487 :         if (!courtesyTimeSig) {
    1102          241 :             courtesyTimeSig = Factory::createTimeSig(courtesySigSeg);
    1103          241 :             courtesyTimeSig->setTrack(track);
    1104          241 :             courtesyTimeSig->setGenerated(true);
    1105          241 :             courtesyTimeSig->setIsCourtesy(true);
    1106          241 :             courtesySigSeg->add(courtesyTimeSig);
    1107              :         }
    1108              : 
    1109              :         // Layout & create shapes
    1110          487 :         courtesyTimeSig->setFrom(actualTimeSig);
    1111          487 :         if (courtesyTimeSig->isStyled(Pid::SCALE)) {
    1112              :             // If this courtesyTimeSig was previously disabled its scale style may have not been updated
    1113          487 :             courtesyTimeSig->setScale(courtesyTimeSig->propertyDefault(Pid::SCALE).value<ScaleF>());
    1114              :         }
    1115              : 
    1116          487 :         TLayout::layoutTimeSig(courtesyTimeSig, courtesyTimeSig->mutldata(), ctx);
    1117              :     }
    1118              : 
    1119        32077 :     if (courtesySigSeg && ((!isContinuationCourtesy && !m->hasCourtesyTimeSig()) || !ctx.conf().styleB(Sid::genCourtesyTimesig))) {
    1120              :         // Whole segment shouldn't be shown, remove any existing courtesy signatures
    1121            3 :         if (!isContinuationCourtesy) {
    1122            3 :             m->setHasCourtesyTimeSig(false);
    1123              :         }
    1124            3 :         if (courtesySigSeg) {
    1125            3 :             courtesySigSeg->setEnabled(false);
    1126              :         }
    1127              :     }
    1128              : 
    1129        32077 :     if (courtesySigSeg && courtesySigSeg->enabled()) {
    1130          359 :         if (courtesySigSeg->hasElements()) {
    1131          353 :             courtesySigSeg->createShapes();
    1132              :         } else {
    1133            6 :             courtesySigSeg->setEnabled(false);
    1134            6 :             if (!isContinuationCourtesy) {
    1135            6 :                 m->setHasCourtesyTimeSig(false);
    1136              :             }
    1137              :         }
    1138              :     }
    1139        32077 : }
    1140              : 
    1141        32203 : void MeasureLayout::setCourtesyKeySig(Measure* m, const Fraction& refSigTick, const Fraction& courtesySigTick,
    1142              :                                       const SegmentType courtesySegType, LayoutContext& ctx)
    1143              : {
    1144              :     // Find original element
    1145        32203 :     const size_t nstaves = ctx.dom().nstaves();
    1146        32203 :     const Fraction courtesySigRTick = courtesySigTick - m->tick();
    1147        32203 :     const Measure* prevMeasure = m->prevMeasureMM();
    1148              : 
    1149        32203 :     const bool isTrailer = courtesySegType == SegmentType::KeySigAnnounce;
    1150        32203 :     const bool isContinuationCourtesy = courtesySegType == SegmentType::KeySigStartRepeatAnnounce;
    1151              : 
    1152              :     const Segment* prevCourtesySegment
    1153        32203 :         = prevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySigRepeatAnnounce, prevMeasure->ticks()) : nullptr;
    1154              : 
    1155              :     // Cont. courtesies - check for sig at the start of the measure OR end of previous measure if changesBeforeBarline... is on
    1156          585 :     const bool checkPrevMeasure = isContinuationCourtesy && prevMeasure
    1157        33066 :                                   && ((prevMeasure->repeatEnd() && ctx.conf().styleB(Sid::changesBeforeBarlineRepeats))
    1158          278 :                                       || (prevMeasure->repeatJump()
    1159          278 :                                           && ctx.conf().styleB(Sid::changesBeforeBarlineOtherJumps)));
    1160        32203 :     const Segment* ksSegAtCourtesyTick = m->findSegmentR(SegmentType::KeySig, courtesySigRTick);
    1161        32647 :     ksSegAtCourtesyTick = !ksSegAtCourtesyTick && checkPrevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySig,
    1162              :                                                                                                courtesySigTick
    1163          444 :                                                                                                - prevMeasure->tick()) : ksSegAtCourtesyTick;
    1164              : 
    1165        32203 :     const bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyKeySig();
    1166              : 
    1167        32203 :     Segment* courtesySigSeg = m->findSegmentR(courtesySegType, courtesySigRTick);
    1168        78668 :     for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
    1169              :         // Find reference signature
    1170        46465 :         const Staff* staff = ctx.dom().staff(track2staff(track));
    1171        46465 :         const Fraction refSigElementTick = staff->currentKeyTick(refSigTick);
    1172        46465 :         const Measure* refMeasure = ctx.dom().tick2measureMM(refSigElementTick);
    1173              :         const Segment* actualKeySigSeg
    1174        46465 :             = refMeasure ? refMeasure->findSegmentR(SegmentType::KeySig, refSigElementTick - refMeasure->tick()) : nullptr;
    1175        46465 :         const EngravingItem* el = actualKeySigSeg ? actualKeySigSeg->element(track) : nullptr;
    1176        46465 :         const KeySig* actualKeySig = el ? toKeySig(el) : nullptr;
    1177              : 
    1178        46465 :         const KeySigEvent refKey = staff->keySigEvent(refSigTick);
    1179              :         // Get info from correct tick for repeats
    1180              :         // For trailers and pre-repeat courtesies, signatures should be different
    1181        46465 :         const bool sigsDifferent = staff->key(m->endTick() - Fraction::eps()) != refKey.key();
    1182        46465 :         const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
    1183        45612 :             track) : sigsDifferent;
    1184              :         // Only show key sig changes on pitched staves
    1185        46465 :         const bool staffIsPitchedAtNextMeas = ctx.dom().lastMeasureMM() == m
    1186        46465 :                                               || (m->nextMeasureMM() && staff->isPitchedStaff(m->nextMeasureMM()->tick()));
    1187              :         // If there is a real key sig at this tick (in this bar or the previous), don't create a courtesy
    1188        46465 :         const bool hasSigAtTick = ksSegAtCourtesyTick && ksSegAtCourtesyTick->enabled() && ksSegAtCourtesyTick->element(track);
    1189              :         // Only show courtesy if its real signature has courtesies enabled
    1190        46465 :         const bool actualShowCourtesy = actualKeySig ? actualKeySig->showCourtesy() : true;
    1191        46465 :         const bool show = actualShowCourtesy && staffIsPitchedAtNextMeas && needsCourtesy && !hasSigAtTick && ctx.conf().styleB(
    1192        46465 :             Sid::genCourtesyKeysig);
    1193              : 
    1194        46465 :         if (!courtesySigSeg) {
    1195        46049 :             if (!show) {
    1196        45806 :                 continue;
    1197              :             }
    1198              : 
    1199              :             // Create a segment if one doesn't already exist
    1200          243 :             courtesySigSeg = Factory::createSegment(m, courtesySegType, courtesySigRTick);
    1201          243 :             m->add(courtesySigSeg);
    1202          243 :             m->setTrailer(m->trailer() || isTrailer);
    1203              :         }
    1204          659 :         if (!isContinuationCourtesy) {
    1205          648 :             m->setHasCourtesyKeySig(true);
    1206              :         }
    1207          659 :         courtesySigSeg->setTrailer(isTrailer);
    1208          659 :         courtesySigSeg->setEnabled(true);
    1209              : 
    1210              :         // Find courtesy element or create if it doesn't exist
    1211          659 :         KeySig* courtesyKeySig = nullptr;
    1212          659 :         EngravingItem* keySigElem = courtesySigSeg->element(track);
    1213          659 :         if (keySigElem && keySigElem->isKeySig()) {
    1214          307 :             courtesyKeySig = toKeySig(keySigElem);
    1215              :         }
    1216              : 
    1217              :         // this key sig shouldn't be shown, remove from segment
    1218          659 :         if (!show) {
    1219           24 :             if (courtesyKeySig) {
    1220            2 :                 courtesySigSeg->remove(courtesyKeySig);
    1221              :             }
    1222           24 :             continue;
    1223              :         }
    1224              : 
    1225          635 :         if (!courtesyKeySig) {
    1226          330 :             courtesyKeySig = Factory::createKeySig(courtesySigSeg);
    1227          330 :             courtesyKeySig->setTrack(track);
    1228          330 :             courtesyKeySig->setGenerated(true);
    1229          330 :             courtesyKeySig->setIsCourtesy(true);
    1230          330 :             courtesySigSeg->add(courtesyKeySig);
    1231              :         }
    1232          635 :         courtesyKeySig->setKeySigEvent(refKey);
    1233              : 
    1234              :         // Layout & create shapes
    1235          635 :         TLayout::layoutKeySig(courtesyKeySig, courtesyKeySig->mutldata(), ctx.conf());
    1236        46465 :     }
    1237              : 
    1238        32203 :     if (courtesySigSeg && ((!isContinuationCourtesy && !m->hasCourtesyKeySig()) || !ctx.conf().styleB(Sid::genCourtesyKeysig))) {
    1239              :         // Whole segment shouldn't be shown, remove any existing courtesy signatures
    1240            0 :         if (!isContinuationCourtesy) {
    1241            0 :             m->setHasCourtesyKeySig(false);
    1242              :         }
    1243            0 :         if (courtesySigSeg) {
    1244            0 :             courtesySigSeg->setEnabled(false);
    1245              :         }
    1246              :     }
    1247              : 
    1248        32203 :     if (courtesySigSeg && courtesySigSeg->enabled()) {
    1249          440 :         if (courtesySigSeg->hasElements()) {
    1250          438 :             courtesySigSeg->createShapes();
    1251              :         } else {
    1252            2 :             courtesySigSeg->setEnabled(false);
    1253            2 :             if (!isContinuationCourtesy) {
    1254            2 :                 m->setHasCourtesyKeySig(false);
    1255              :             }
    1256              :         }
    1257              :     }
    1258        32203 : }
    1259              : 
    1260         1286 : void MeasureLayout::setCourtesyClef(Measure* m, const Fraction& refClefTick, const Fraction& courtesyClefTick,
    1261              :                                     const SegmentType courtesySegType, LayoutContext& ctx)
    1262              : {
    1263              :     // Find original element
    1264         1286 :     const size_t nstaves = ctx.dom().nstaves();
    1265         1286 :     const Fraction courtesyClefRTick = courtesyClefTick - m->tick();
    1266         1286 :     const Measure* prevMeasure = m->prevMeasureMM();
    1267              : 
    1268         1286 :     const bool isContinuationCourtesy = courtesySegType == SegmentType::ClefStartRepeatAnnounce;
    1269              : 
    1270              :     const Segment* prevCourtesySegment
    1271         1286 :         = prevMeasure ? prevMeasure->findSegmentR(SegmentType::ClefRepeatAnnounce, prevMeasure->ticks()) : nullptr;
    1272         1286 :     const Segment* clefSegAtCourtesyTick = m->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, courtesyClefRTick);
    1273              :     clefSegAtCourtesyTick
    1274         1286 :         = !clefSegAtCourtesyTick
    1275         1286 :           && prevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySig, courtesyClefTick - prevMeasure->tick()) : clefSegAtCourtesyTick;
    1276              : 
    1277         1286 :     bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyClef();
    1278              : 
    1279         1286 :     Segment* courtesyClefSeg = m->findSegmentR(courtesySegType, courtesyClefRTick);
    1280         3217 :     for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
    1281         1931 :         const Staff* staff = ctx.dom().staff(track2staff(track));
    1282         1931 :         const Fraction refClefElementTick = staff->currentClefTick(refClefTick);
    1283         1931 :         const Measure* refMeasure = ctx.dom().tick2measureMM(refClefElementTick);
    1284              :         const Segment* actualClefSeg
    1285         3862 :             = refMeasure ? refMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef,
    1286         1931 :                                                     refClefElementTick - refMeasure->tick()) : nullptr;
    1287         1931 :         if (!actualClefSeg && refMeasure && refMeasure->prevMeasureMM()) {
    1288              :             // Check previous measure
    1289           17 :             Measure* refPrevMeasure = refMeasure->prevMeasureMM();
    1290              :             actualClefSeg
    1291           17 :                 = refPrevMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, refClefElementTick - refPrevMeasure->tick());
    1292              :         }
    1293         1931 :         const EngravingItem* el = actualClefSeg ? actualClefSeg->element(track) : nullptr;
    1294         1931 :         const Clef* actualClef = el ? toClef(el) : nullptr;
    1295              : 
    1296         1931 :         const ClefType refClef = staff->clef(refClefTick);
    1297              :         // For trailers and pre-repeat courtesies, clefs should be different
    1298         1931 :         const bool clefsDifferent = staff->clef(m->endTick() - Fraction::eps()) != refClef;
    1299         1931 :         const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
    1300         1078 :             track) : clefsDifferent;
    1301              :         // If there is a real clef at this tick (in this bar or the previous), don't create a courtesy
    1302         1931 :         const bool hasClefAtTick = clefSegAtCourtesyTick && clefSegAtCourtesyTick->enabled() && clefSegAtCourtesyTick->element(track);
    1303              :         // Only show courtesy if its real clef has courtesies enabled
    1304         1931 :         const bool actualShowCourtesy = actualClef && actualClef->showCourtesy();
    1305         1931 :         const bool show = actualShowCourtesy && needsCourtesy && !hasClefAtTick && ctx.conf().styleB(Sid::genCourtesyClef);
    1306              : 
    1307         1931 :         if (!courtesyClefSeg) {
    1308         1904 :             if (!show) {
    1309         1904 :                 continue;
    1310              :             }
    1311              : 
    1312              :             // Create a segment if one doesn't already exist
    1313           10 :             courtesyClefSeg = Factory::createSegment(m, courtesySegType, courtesyClefRTick);
    1314           10 :             m->add(courtesyClefSeg);
    1315           10 :             courtesyClefSeg->setTrailer(false);
    1316              :         }
    1317           37 :         if (!isContinuationCourtesy) {
    1318           19 :             m->setHasCourtesyClef(true);
    1319              :         }
    1320           37 :         courtesyClefSeg->setEnabled(true);
    1321              : 
    1322              :         // Find courtesy element or create if it doesn't exist
    1323           37 :         Clef* courtesyClef = nullptr;
    1324           37 :         EngravingItem* clefElem = courtesyClefSeg->element(track);
    1325           37 :         if (clefElem && clefElem->isClef()) {
    1326           17 :             courtesyClef = toClef(clefElem);
    1327              :         }
    1328              : 
    1329              :         // this clef shouldn't be shown, remove from segment
    1330           37 :         if (!show) {
    1331           10 :             if (courtesyClef) {
    1332            0 :                 courtesyClefSeg->remove(courtesyClef);
    1333              :             }
    1334           10 :             continue;
    1335              :         }
    1336              : 
    1337           27 :         if (!courtesyClef) {
    1338           10 :             courtesyClef = Factory::createClef(courtesyClefSeg);
    1339           10 :             courtesyClef->setTrack(track);
    1340           10 :             courtesyClef->setGenerated(true);
    1341           10 :             courtesyClef->setSmall(true);
    1342           10 :             courtesyClef->setClefType(actualClef->clefType());
    1343           10 :             courtesyClef->setIsCourtesy(true);
    1344           10 :             courtesyClefSeg->add(courtesyClef);
    1345              :         }
    1346              : 
    1347              :         // Layout & create shapes
    1348           27 :         TLayout::layoutClef(courtesyClef, courtesyClef->mutldata(), ctx.conf());
    1349              :     }
    1350              : 
    1351         1286 :     if (courtesyClefSeg && (!ctx.conf().styleB(Sid::genCourtesyClef) || (!isContinuationCourtesy && !m->hasCourtesyClef()))) {
    1352              :         // Whole segment shouldn't be shown, remove any existing courtesy signatures
    1353            0 :         if (!isContinuationCourtesy) {
    1354            0 :             m->setHasCourtesyClef(false);
    1355              :         }
    1356            0 :         if (courtesyClefSeg) {
    1357            0 :             courtesyClefSeg->setEnabled(false);
    1358              :         }
    1359              :     }
    1360              : 
    1361         1286 :     if (courtesyClefSeg && courtesyClefSeg->enabled()) {
    1362           27 :         if (courtesyClefSeg->hasElements()) {
    1363           27 :             courtesyClefSeg->createShapes();
    1364              :         } else {
    1365            0 :             courtesyClefSeg->setEnabled(false);
    1366            0 :             if (isContinuationCourtesy) {
    1367            0 :                 m->setHasCourtesyClef(false);
    1368              :             }
    1369              :         }
    1370              :     }
    1371         1286 : }
    1372              : 
    1373           82 : static void calcParenTopBottom(Parenthesis* item, double& top, double& bottom, LayoutContext& ctx)
    1374              : {
    1375           82 :     EngravingItem* parent = item->layoutParent();
    1376           82 :     const double spatium = item->spatium();
    1377           82 :     if (!parent) {
    1378            0 :         return;
    1379              :     }
    1380              : 
    1381           82 :     if (!parent->ldata()->isValid()) {
    1382            0 :         TLayout::layoutItem(parent, ctx);
    1383              :     }
    1384              : 
    1385           82 :     RectF bbox = parent->ldata()->bbox();
    1386              : 
    1387           82 :     top = std::min(top, bbox.top() + parent->pos().y() + spatium / 4);
    1388           82 :     bottom = std::max(bottom, bbox.bottom() + parent->pos().y() - spatium / 4);
    1389              : }
    1390              : 
    1391         1309 : void MeasureLayout::addRepeatCourtesyParentheses(Measure* m, const bool continuation, LayoutContext& ctx)
    1392              : {
    1393         1309 :     const SegmentType tsSegType = continuation ? SegmentType::TimeSigStartRepeatAnnounce : SegmentType::TimeSigRepeatAnnounce;
    1394         1309 :     const SegmentType ksSegType = continuation ? SegmentType::KeySigStartRepeatAnnounce : SegmentType::KeySigRepeatAnnounce;
    1395         1309 :     const SegmentType clefSegType = continuation ? SegmentType::ClefStartRepeatAnnounce : SegmentType::ClefRepeatAnnounce;
    1396              : 
    1397         1309 :     const Fraction sigTick = continuation ? Fraction(0, 1) : m->ticks();
    1398              : 
    1399        22295 :     auto elShouldHaveParenthesis = [&](const Segment* seg, const track_idx_t track) -> bool {
    1400        22295 :         if (!seg || !seg->enabled() || track > ctx.dom().ntracks()) {
    1401        21906 :             return false;
    1402              :         }
    1403              : 
    1404          389 :         const Staff* staff = ctx.dom().staff(track2staff(track));
    1405          389 :         if (!staff) {
    1406          140 :             return false;
    1407              :         }
    1408          249 :         const StaffType* st = staff->staffType(seg->tick());
    1409          249 :         const bool noTimesig = st && seg->isType(SegmentType::TimeSigTypes) && !st->genTimesig();
    1410          249 :         const bool noKeysig = st && seg->isType(SegmentType::KeySigTypes) && !st->genKeysig();
    1411          249 :         const bool noClef = st && seg->isType(SegmentType::ClefTypes) && !st->genClef();
    1412          249 :         if (noTimesig || noKeysig || noClef) {
    1413            0 :             return false;
    1414              :         }
    1415              : 
    1416          249 :         const EngravingItem* el = seg->element(track);
    1417          249 :         return el && el->visible();
    1418         1309 :     };
    1419              : 
    1420         3185 :     auto timeSigShouldHaveOwnParentheses = [&](const Segment* seg, const track_idx_t track) -> bool {
    1421         3185 :         if (!elShouldHaveParenthesis(seg, track)) {
    1422         3156 :             return false;
    1423              :         }
    1424              : 
    1425           29 :         const EngravingItem* el = seg ? seg->element(track) : nullptr;
    1426           29 :         if (!el || !el->isTimeSig()) {
    1427            0 :             return false;
    1428              :         }
    1429              : 
    1430           29 :         return ctx.conf().styleV(Sid::timeSigPlacement).value<TimeSigPlacement>() != TimeSigPlacement::NORMAL;
    1431         1309 :     };
    1432              : 
    1433         3185 :     auto createParenthesesForSegments = [&](Segment* leftSeg, Segment* rightSeg, track_idx_t track) -> void {
    1434         3185 :         double top = DBL_MAX;
    1435         3185 :         double bottom = -DBL_MAX;
    1436         3185 :         EngravingItem* leftItem = leftSeg ? leftSeg->element(track) : nullptr;
    1437         3185 :         EngravingItem* rightItem = rightSeg ? rightSeg->element(track) : nullptr;
    1438         3185 :         Parenthesis* leftParen = nullptr;
    1439         3185 :         if (leftItem) {
    1440           41 :             leftItem->setParenthesesMode(leftItem->rightParen() ? ParenthesesMode::BOTH : ParenthesesMode::LEFT, true, true);
    1441           41 :             leftParen = leftItem->leftParen();
    1442              :         }
    1443         3185 :         Parenthesis* rightParen = nullptr;
    1444         3185 :         if (rightItem) {
    1445           41 :             rightItem->setParenthesesMode(rightItem->leftParen() ? ParenthesesMode::BOTH : ParenthesesMode::RIGHT, true, true);
    1446           41 :             rightParen = rightItem->rightParen();
    1447              :         }
    1448           41 :         bool needsBigTimeSigAdjust = leftSeg && rightSeg && leftSeg == rightSeg && leftSeg->isType(SegmentType::TimeSigTypes)
    1449         3226 :                                      && ctx.conf().styleV(Sid::timeSigPlacement).value<TimeSigPlacement>()
    1450         3185 :                                      != TimeSigPlacement::NORMAL;
    1451         3185 :         if ((ctx.conf().styleB(Sid::smallParens) || needsBigTimeSigAdjust) && leftParen && rightParen) {
    1452           41 :             const double spatium = leftParen->spatium();
    1453           41 :             calcParenTopBottom(leftParen, top, bottom, ctx);
    1454           41 :             calcParenTopBottom(rightParen, top, bottom, ctx);
    1455              : 
    1456           41 :             double height = bottom - top;
    1457              : 
    1458           41 :             if (!ctx.conf().styleB(Sid::smallParens)) {
    1459            0 :                 top -= 1.25 * spatium;
    1460            0 :                 height += 2.5 * spatium;
    1461              :             }
    1462              : 
    1463           41 :             rightParen->mutldata()->startY.set_value(top);
    1464           41 :             rightParen->mutldata()->height.set_value(height);
    1465           41 :             rightParen->mutldata()->midPointThickness.set_value(height / 60 * rightParen->ldata()->mag());  // 0.1sp for a height of 6sp
    1466           41 :             leftParen->mutldata()->startY.set_value(top);
    1467           41 :             leftParen->mutldata()->height.set_value(height);
    1468           41 :             leftParen->mutldata()->midPointThickness.set_value(height / 60 * leftParen->ldata()->mag());  // 0.1sp for a height of 6sp
    1469              : 
    1470           41 :             double mag = std::max(leftParen->ldata()->mag(), rightParen->ldata()->mag());
    1471           41 :             leftParen->mutldata()->setMag(mag);
    1472           41 :             rightParen->mutldata()->setMag(mag);
    1473         3144 :         } else if (leftParen || rightParen) {
    1474            0 :             const Staff* staff = leftParen ? leftParen->staff() : rightParen->staff();
    1475            0 :             const double spatium = leftParen ? leftParen->spatium() : rightParen->spatium();
    1476            0 :             const Fraction tick = leftParen ? leftParen->tick() : rightParen->tick();
    1477            0 :             if (leftParen) {
    1478            0 :                 leftParen->mutldata()->startY.set_value(-spatium);
    1479            0 :                 leftParen->mutldata()->height.set_value(staff->staffHeight(tick) + 2 * spatium * leftParen->mag());
    1480            0 :                 leftParen->mutldata()->midPointThickness.set_value(leftParen->ldata()->height / 60 * leftParen->ldata()->mag());  // 0.1sp for a height of 6sp
    1481              :             }
    1482            0 :             if (rightParen) {
    1483            0 :                 rightParen->mutldata()->startY.set_value(-spatium);
    1484            0 :                 rightParen->mutldata()->height.set_value(staff->staffHeight(tick) + 2 * spatium * rightParen->mag());
    1485            0 :                 rightParen->mutldata()->midPointThickness.set_value(rightParen->ldata()->height / 60 * rightParen->ldata()->mag());  // 0.1sp for a height of 6sp
    1486              :             }
    1487              :         }
    1488              : 
    1489         3185 :         if (leftParen) {
    1490           41 :             ParenthesisLayout::layoutParentheses(leftItem, ctx);
    1491              :         }
    1492              : 
    1493         3185 :         if (rightParen && rightItem != leftItem) {
    1494           25 :             ParenthesisLayout::layoutParentheses(rightItem, ctx);
    1495              :         }
    1496         3185 :     };
    1497              : 
    1498         4494 :     for (track_idx_t track = 0; track <= ctx.dom().nstaves() * VOICES; track += VOICES) {
    1499         3185 :         Segment* clefSeg = m->findSegmentR(clefSegType, sigTick);
    1500         3185 :         Segment* ksSeg = m->findSegmentR(ksSegType, sigTick);
    1501         3185 :         Segment* tsSeg = m->findSegmentR(tsSegType, sigTick);
    1502         3185 :         bool separateTsParens = timeSigShouldHaveOwnParentheses(tsSeg, track);
    1503              : 
    1504         3185 :         Segment* leftMostSeg = clefSeg;
    1505              : 
    1506         3185 :         if (!elShouldHaveParenthesis(leftMostSeg, track)) {
    1507         3158 :             leftMostSeg = ksSeg;
    1508              :         }
    1509              : 
    1510         3185 :         if (!separateTsParens && !elShouldHaveParenthesis(leftMostSeg, track)) {
    1511         3148 :             leftMostSeg = tsSeg;
    1512              :         }
    1513              : 
    1514         3185 :         if (!elShouldHaveParenthesis(leftMostSeg, track)) {
    1515         3144 :             leftMostSeg = nullptr;
    1516              :         }
    1517              : 
    1518              :         // Remove stale parentheses
    1519        12740 :         for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
    1520         9555 :             if (seg == leftMostSeg || !seg || (seg == tsSeg && separateTsParens) || !seg->element(track)) {
    1521         9515 :                 continue;
    1522              :             }
    1523           40 :             EngravingItem* item = seg->element(track);
    1524           40 :             removeRepeatCourtesyParenthesis(item, DirectionH::LEFT);
    1525              :         }
    1526              : 
    1527         3185 :         Segment* rightMostSeg = separateTsParens ? nullptr : tsSeg;
    1528              : 
    1529         3185 :         if (!elShouldHaveParenthesis(rightMostSeg, track)) {
    1530         3156 :             rightMostSeg = ksSeg;
    1531              :         }
    1532              : 
    1533         3185 :         if (!elShouldHaveParenthesis(rightMostSeg, track)) {
    1534         3156 :             rightMostSeg = clefSeg;
    1535              :         }
    1536              : 
    1537         3185 :         if (!elShouldHaveParenthesis(rightMostSeg, track)) {
    1538         3144 :             rightMostSeg = nullptr;
    1539              :         }
    1540              : 
    1541              :         // Remove stale parentheses
    1542        12740 :         for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
    1543         9555 :             if (seg == rightMostSeg || !seg || (seg == tsSeg && separateTsParens) || !seg->element(track)) {
    1544         9515 :                 continue;
    1545              :             }
    1546           40 :             EngravingItem* item = seg->element(track);
    1547           40 :             removeRepeatCourtesyParenthesis(item, DirectionH::RIGHT);
    1548              :         }
    1549              : 
    1550         3185 :         createParenthesesForSegments(leftMostSeg, rightMostSeg, track);
    1551              : 
    1552         3185 :         if (separateTsParens) {
    1553            0 :             createParenthesesForSegments(tsSeg, tsSeg, track);
    1554              :         }
    1555              :     }
    1556         1309 : }
    1557              : 
    1558       109445 : void MeasureLayout::removeRepeatCourtesyParenthesesMeasure(Measure* m, const bool continuation, LayoutContext& ctx)
    1559              : {
    1560       109445 :     const SegmentType tsSegType = continuation ? SegmentType::TimeSigStartRepeatAnnounce : SegmentType::TimeSigRepeatAnnounce;
    1561       109445 :     const SegmentType ksSegType = continuation ? SegmentType::KeySigStartRepeatAnnounce : SegmentType::KeySigRepeatAnnounce;
    1562       109445 :     const SegmentType clefSegType = continuation ? SegmentType::ClefStartRepeatAnnounce : SegmentType::ClefRepeatAnnounce;
    1563              : 
    1564       109445 :     const Fraction sigTick = continuation ? Fraction(0, 1) : m->ticks();
    1565              : 
    1566       109445 :     Segment* clefSeg = m->findSegmentR(clefSegType, sigTick);
    1567       109445 :     Segment* ksSeg = m->findSegmentR(ksSegType, sigTick);
    1568       109445 :     Segment* tsSeg = m->findSegmentR(tsSegType, sigTick);
    1569              : 
    1570       437780 :     for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
    1571       328335 :         if (!seg) {
    1572       328335 :             continue;
    1573              :         }
    1574            0 :         for (track_idx_t track = 0; track <= ctx.dom().nstaves() * VOICES; track += VOICES) {
    1575            0 :             EngravingItem* item = seg->element(track);
    1576            0 :             if (!item) {
    1577            0 :                 continue;
    1578              :             }
    1579            0 :             removeRepeatCourtesyParenthesis(item);
    1580              :         }
    1581              :     }
    1582       109445 : }
    1583              : 
    1584           80 : void MeasureLayout::removeRepeatCourtesyParenthesis(EngravingItem* item, const DirectionH direction)
    1585              : {
    1586           80 :     if (!item) {
    1587            0 :         return;
    1588              :     }
    1589           80 :     if (direction == DirectionH::AUTO) {
    1590            0 :         if (Parenthesis* leftParen = item->leftParen()) {
    1591            0 :             item->remove(leftParen);
    1592              :         }
    1593            0 :         if (Parenthesis* rightParen = item->rightParen()) {
    1594            0 :             item->remove(rightParen);
    1595              :         }
    1596            0 :         return;
    1597              :     }
    1598              : 
    1599           80 :     Parenthesis* paren = item->paren(direction);
    1600           80 :     if (!paren) {
    1601           80 :         return;
    1602              :     }
    1603              : 
    1604            0 :     item->remove(paren);
    1605              : }
    1606              : 
    1607        55377 : void MeasureLayout::setRepeatCourtesiesAndParens(Measure* m, LayoutContext& ctx)
    1608              : {
    1609        55377 :     const bool showCourtesyRepeats = m->repeatEnd() && ctx.conf().styleB(Sid::showCourtesiesRepeats);
    1610        55377 :     const bool showCourtesyOtherJumps = m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps);
    1611              : 
    1612        55377 :     if (showCourtesyRepeats) {
    1613          416 :         MeasureLayout::addRepeatCourtesies(m, ctx);
    1614          416 :         if (ctx.conf().styleB(Sid::useParensRepeatCourtesies)) {
    1615          416 :             MeasureLayout::addRepeatCourtesyParentheses(m, false, ctx);
    1616              :         } else {
    1617            0 :             MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
    1618              :         }
    1619              :     }
    1620              : 
    1621        55377 :     if (showCourtesyOtherJumps) {
    1622          308 :         MeasureLayout::addRepeatCourtesies(m, ctx);
    1623          308 :         if (ctx.conf().styleB(Sid::useParensOtherJumpCourtesies)) {
    1624          308 :             MeasureLayout::addRepeatCourtesyParentheses(m, false, ctx);
    1625              :         } else {
    1626            0 :             MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
    1627              :         }
    1628              :     }
    1629              : 
    1630        55377 :     if (!showCourtesyRepeats && !showCourtesyOtherJumps) {
    1631        54653 :         MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
    1632        54653 :         removeRepeatCourtesies(m);
    1633              :     }
    1634              : 
    1635       103896 :     const bool courtesiesAfterCancellingRepeats = m->prevMeasureMM() && m->prevMeasureMM()->repeatEnd()
    1636          521 :                                                   && ctx.conf().styleB(Sid::showCourtesiesAfterCancellingRepeats)
    1637       103896 :                                                   && ctx.conf().styleB(Sid::showCourtesiesRepeats);
    1638       103896 :     const bool courtesiesAfterCancellingOtherJumps = m->prevMeasureMM() && m->prevMeasureMM()->repeatJump()
    1639          436 :                                                      && ctx.conf().styleB(Sid::showCourtesiesAfterCancellingOtherJumps)
    1640       103896 :                                                      && ctx.conf().styleB(Sid::showCourtesiesOtherJumps);
    1641        55377 :     if (courtesiesAfterCancellingRepeats) {
    1642          307 :         MeasureLayout::addRepeatContinuationCourtesies(m, ctx);
    1643          307 :         if (ctx.conf().styleB(Sid::useParensRepeatCourtesiesAfterCancelling)) {
    1644          307 :             MeasureLayout::addRepeatCourtesyParentheses(m, true, ctx);
    1645              :         } else {
    1646            0 :             MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
    1647              :         }
    1648              :     }
    1649              : 
    1650        55377 :     if (courtesiesAfterCancellingOtherJumps) {
    1651          278 :         MeasureLayout::addRepeatContinuationCourtesies(m, ctx);
    1652          278 :         if (ctx.conf().styleB(Sid::useParensOtherJumpCourtesiesAfterCancelling)) {
    1653          278 :             MeasureLayout::addRepeatCourtesyParentheses(m, true, ctx);
    1654              :         } else {
    1655            0 :             MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
    1656              :         }
    1657              :     }
    1658              : 
    1659        55377 :     if (!courtesiesAfterCancellingRepeats && !courtesiesAfterCancellingOtherJumps) {
    1660        54792 :         MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
    1661        54792 :         removeRepeatContinuationCourtesies(m);
    1662              :     }
    1663        55377 : }
    1664              : 
    1665          724 : void MeasureLayout::addRepeatCourtesies(Measure* m, LayoutContext& ctx)
    1666              : {
    1667          724 :     const std::vector<Measure*> measures = findFollowingRepeatMeasures(m);
    1668          724 :     if (measures.empty()) {
    1669           91 :         removeRepeatCourtesies(m);
    1670           91 :         return;
    1671              :     }
    1672              : 
    1673          633 :     bool hasCourtesies = false;
    1674         1385 :     for (Measure* repeatStartMeasure : measures) {
    1675              :         // Follow section break courtesy property
    1676          752 :         const Measure* prevMeasure = repeatStartMeasure->prevMeasureMM();
    1677          752 :         const LayoutBreak* sectionBreak = prevMeasure ? prevMeasure->sectionBreakElement() : nullptr;
    1678          752 :         const bool sectionBreakHideCourtesies = sectionBreak && !sectionBreak->showCourtesy();
    1679              : 
    1680          752 :         if (repeatStartMeasure == m->nextMeasureMM() || sectionBreakHideCourtesies) {
    1681           51 :             continue;
    1682              :         }
    1683          701 :         setCourtesyClef(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::ClefRepeatAnnounce, ctx);
    1684          701 :         setCourtesyKeySig(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::KeySigRepeatAnnounce, ctx);
    1685          701 :         setCourtesyTimeSig(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::TimeSigRepeatAnnounce, ctx);
    1686              : 
    1687          701 :         hasCourtesies = true;
    1688              :     }
    1689              : 
    1690          633 :     if (!hasCourtesies) {
    1691           10 :         removeRepeatCourtesies(m);
    1692              :     }
    1693          724 : }
    1694              : 
    1695        54754 : void MeasureLayout::removeRepeatCourtesies(Measure* m)
    1696              : {
    1697       111320 :     for (Segment* seg = m->last(); seg != m->first(); seg = seg->prev()) {
    1698        80091 :         if (seg->isChordRestType()) {
    1699        23525 :             break;
    1700              :         }
    1701        56566 :         if (!seg->isType(SegmentType::ClefRepeatAnnounce | SegmentType::TimeSigRepeatAnnounce | SegmentType::KeySigRepeatAnnounce)) {
    1702        56566 :             continue;
    1703              :         }
    1704            0 :         seg->mutldata()->reset();
    1705              : 
    1706            0 :         if (seg->enabled()) {
    1707            0 :             seg->setEnabled(false);
    1708              :         }
    1709              :     }
    1710        54754 :     m->setHasCourtesyClef(false);
    1711        54754 :     m->setHasCourtesyKeySig(false);
    1712        54754 :     m->setHasCourtesyTimeSig(false);
    1713        54754 : }
    1714              : 
    1715          585 : void MeasureLayout::addRepeatContinuationCourtesies(Measure* m, LayoutContext& ctx)
    1716              : {
    1717          585 :     setCourtesyTimeSig(m, m->tick(), m->tick(), SegmentType::TimeSigStartRepeatAnnounce, ctx);
    1718          585 :     setCourtesyKeySig(m, m->tick(), m->tick(), SegmentType::KeySigStartRepeatAnnounce, ctx);
    1719          585 :     setCourtesyClef(m, m->tick(), m->tick(), SegmentType::ClefStartRepeatAnnounce, ctx);
    1720          585 : }
    1721              : 
    1722        54792 : void MeasureLayout::removeRepeatContinuationCourtesies(Measure* m)
    1723              : {
    1724        94742 :     for (Segment* seg = m->first(); seg != m->last(); seg = seg->next()) {
    1725        94616 :         if (seg->isChordRestType()) {
    1726        54666 :             break;
    1727              :         }
    1728        39950 :         if (!seg->isType(SegmentType::ClefStartRepeatAnnounce | SegmentType::TimeSigStartRepeatAnnounce
    1729              :                          | SegmentType::KeySigStartRepeatAnnounce)) {
    1730        39950 :             continue;
    1731              :         }
    1732              : 
    1733            0 :         seg->mutldata()->reset();
    1734              : 
    1735            0 :         if (seg->enabled()) {
    1736            0 :             seg->setEnabled(false);
    1737              :         }
    1738              :     }
    1739        54792 : }
    1740              : 
    1741        17654 : Segment* MeasureLayout::addHeaderClef(Measure* m, bool isFirstClef, const Staff* staff, LayoutContext& ctx)
    1742              : {
    1743        17654 :     const staff_idx_t staffIdx = staff->idx();
    1744        17654 :     const track_idx_t track = staffIdx * VOICES;
    1745        17654 :     Segment* cSegment = m->findFirstR(SegmentType::HeaderClef, Fraction(0, 1));
    1746        17654 :     const StaffType* staffType = staff->staffType(m->tick());
    1747              : 
    1748        17654 :     const bool hideClef = staffType->isTabStaff() ? ctx.conf().styleB(Sid::hideTabClefAfterFirst) : !ctx.conf().styleB(Sid::genClef);
    1749              : 
    1750              :     // find the clef type at the previous tick
    1751        17654 :     ClefTypeList cl = staff->clefType(m->tick() - Fraction::eps());
    1752        17654 :     bool showCourtesy = true;
    1753        17654 :     Segment* s = nullptr;
    1754        17654 :     if (m->prevMeasure()) {
    1755              :         // look for a clef change at the end of the previous measure
    1756         6911 :         s = m->prevMeasure()->findSegment(SegmentType::Clef, m->tick());
    1757        10743 :     } else if (m->isMMRest()) {
    1758              :         // look for a header clef at the beginning of the first underlying measure
    1759          111 :         s = m->mmRestFirst()->findFirstR(SegmentType::HeaderClef, Fraction(0, 1));
    1760              :     }
    1761        17654 :     if (s) {
    1762          257 :         Clef* c = toClef(s->element(track));
    1763          257 :         if (c) {
    1764          195 :             cl = c->clefTypeList();
    1765          195 :             showCourtesy = c->showCourtesy();
    1766              :         }
    1767              :     }
    1768        17654 :     Clef* clef = nullptr;
    1769        17654 :     if (cSegment) {
    1770        14366 :         clef = toClef(cSegment->element(track));
    1771              :     }
    1772        17654 :     if (staff->staffTypeForElement(m)->genClef() && (isFirstClef || !hideClef)) {
    1773        17570 :         if (!cSegment) {
    1774         3280 :             cSegment = Factory::createSegment(m, SegmentType::HeaderClef, Fraction(0, 1));
    1775         3280 :             m->add(cSegment);
    1776              :         }
    1777        17570 :         cSegment->setHeader(true);
    1778        17570 :         if (!clef) {
    1779              :             //
    1780              :             // create missing clef
    1781              :             //
    1782         5021 :             clef = Factory::createClef(cSegment);
    1783         5021 :             clef->setTrack(track);
    1784         5021 :             clef->setGenerated(true);
    1785         5021 :             clef->setShowCourtesy(showCourtesy);
    1786         5021 :             cSegment->add(clef);
    1787              :         }
    1788        17570 :         if (clef->generated()) {
    1789        13233 :             clef->setClefType(cl);
    1790              :         }
    1791        17570 :         clef->setSmall(false);
    1792        17570 :         clef->mutldata()->reset();
    1793        17570 :         TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
    1794        17570 :         cSegment->setEnabled(true);
    1795           84 :     } else if (clef) {
    1796            0 :         clef->ownershipParentItem()->remove(clef);
    1797            0 :         if (clef->generated()) {
    1798            0 :             delete clef;
    1799              :         }
    1800              :     }
    1801              : 
    1802        17654 :     return cSegment;
    1803              : }
    1804              : 
    1805        17654 : Segment* MeasureLayout::addHeaderKeySig(Measure* m, bool isFirstKeysig, const Staff* staff, LayoutContext& ctx)
    1806              : {
    1807        17654 :     const staff_idx_t staffIdx = staff->idx();
    1808        17654 :     const track_idx_t track = staffIdx * VOICES;
    1809        17654 :     Segment* kSegment = m->findFirstR(SegmentType::KeySig, Fraction(0, 1));
    1810              :     // If we need a Key::C KeySig (which would be invisible) and there is
    1811              :     // a courtesy key sig, don’t create it and switch generated flags.
    1812              :     // This avoids creating an invisible KeySig which can distort layout.
    1813              : 
    1814        17654 :     KeySigEvent keyIdx = staff->keySigEvent(m->tick());
    1815        17654 :     KeySig* ksAnnounce = 0;
    1816        17654 :     if ((isFirstKeysig || ctx.conf().styleB(Sid::genKeysig)) && (keyIdx.key() == Key::C)) {
    1817        16105 :         Measure* pm = m->prevMeasureMM();
    1818        16105 :         if (pm && pm->hasCourtesyKeySig()) {
    1819            8 :             Segment* ks = pm->first(SegmentType::KeySigAnnounce);
    1820            8 :             if (ks) {
    1821            0 :                 ksAnnounce = toKeySig(ks->element(track));
    1822            0 :                 if (ksAnnounce) {
    1823            0 :                     isFirstKeysig = false;
    1824              :                     //                                    if (keysig) {
    1825              :                     //                                          ksAnnounce->setGenerated(false);
    1826              :                     //TODO                                      keysig->setGenerated(true);
    1827              :                     //                                          }
    1828              :                 }
    1829              :             }
    1830              :         }
    1831              :     }
    1832              : 
    1833        17654 :     bool isPitchedStaff = staff->isPitchedStaff(m->tick());
    1834              : 
    1835        17654 :     KeySig* keysig = nullptr;
    1836        17654 :     if (kSegment) {
    1837        13725 :         keysig = toKeySig(kSegment->element(track));
    1838              :     }
    1839              :     // keep key sigs in TABs: TABs themselves should hide them
    1840        17654 :     if ((isFirstKeysig || ctx.conf().styleB(Sid::genKeysig)) && isPitchedStaff) {
    1841        16202 :         if (!kSegment) {
    1842         3025 :             kSegment = Factory::createSegment(m, SegmentType::KeySig, Fraction(0, 1));
    1843         3025 :             m->add(kSegment);
    1844              :         }
    1845        16202 :         kSegment->setHeader(true);
    1846        16202 :         if (!keysig) {
    1847              :             //
    1848              :             // create missing key signature
    1849              :             //
    1850         4524 :             keysig = Factory::createKeySig(kSegment);
    1851         4524 :             keysig->setTrack(track);
    1852         4524 :             keysig->setGenerated(true);
    1853         4524 :             kSegment->add(keysig);
    1854              :         }
    1855        16202 :         keysig->setKeySigEvent(keyIdx);
    1856        16202 :         keysig->mutldata()->reset();
    1857        16202 :         TLayout::layoutKeySig(keysig, keysig->mutldata(), ctx.conf());
    1858        16202 :         kSegment->setEnabled(true);
    1859         1452 :     } else if (keysig && isPitchedStaff) {
    1860              :         // do not remove user modified keysigs
    1861            0 :         bool remove = true;
    1862            0 :         EngravingItem* e = kSegment->element(staffIdx * VOICES);
    1863            0 :         Key key = staff->key(m->tick());
    1864            0 :         if ((e && !e->generated()) || (key != keyIdx.key())) {
    1865            0 :             remove = false;
    1866              :         }
    1867              : 
    1868            0 :         if (remove) {
    1869            0 :             keysig->ownershipParentItem()->remove(keysig);
    1870            0 :             if (keysig->generated()) {
    1871            0 :                 delete keysig;
    1872              :             }
    1873              :         }
    1874              :     }
    1875              : 
    1876        17654 :     return kSegment;
    1877        17654 : }
    1878              : 
    1879              : //-------------------------------------------------------------------
    1880              : //   addSystemHeader
    1881              : ///   Add elements to make this measure suitable as the first measure
    1882              : ///   of a system.
    1883              : //    The system header can contain a starting BarLine, a Clef,
    1884              : //    and a KeySig
    1885              : //-------------------------------------------------------------------
    1886              : 
    1887        11459 : void MeasureLayout::addSystemHeader(Measure* m, bool isFirstSystem, LayoutContext& ctx)
    1888              : {
    1889        11459 :     int staffIdx = 0;
    1890        11459 :     Segment* kSegment = nullptr;
    1891        11459 :     Segment* cSegment = nullptr;
    1892              : 
    1893        29113 :     for (const Staff* staff : ctx.dom().staves()) {
    1894        17654 :         const int track = staffIdx * VOICES;
    1895              : 
    1896              :         // Check if this is the first VISIBLE appearance
    1897        17654 :         bool isFirstClef = true;
    1898        17654 :         bool isFirstKeySig = true;
    1899        17654 :         if (!isFirstSystem) {
    1900        11369 :             const Fraction clefTick = staff->currentClefTick(m->tick());
    1901        11369 :             const Fraction keySigTick = staff->currentKeyTick(m->tick());
    1902              :             // Get first measure whether MMR or not
    1903        11369 :             Measure* searchMeasure = ctx.mutDom().tick2measure(std::min(clefTick, keySigTick));
    1904        11369 :             searchMeasure = searchMeasure->hasMMRest()
    1905        11369 :                             && ctx.conf().styleB(Sid::createMultiMeasureRests) ? searchMeasure->mmRest() : searchMeasure;
    1906        24674 :             while (searchMeasure->tick() < m->tick() && (isFirstClef || isFirstKeySig)) {
    1907        13305 :                 const System* sys = searchMeasure->system();
    1908        13305 :                 if (isFirstClef && searchMeasure->tick() >= clefTick) {
    1909              :                     // Need to check previous measure for clef change if one not found in this measure
    1910         8784 :                     Segment* clefSeg = searchMeasure->findFirstR(SegmentType::Clef | SegmentType::HeaderClef, Fraction(0, 1));
    1911         8784 :                     Measure* prevMeas = searchMeasure->prevMeasure();
    1912         8784 :                     if (prevMeas && !clefSeg) {
    1913         1928 :                         clefSeg = prevMeas->findSegment(SegmentType::Clef, m->tick());
    1914              :                     }
    1915         8784 :                     if (clefSeg && clefSeg->enabled()) {
    1916         6815 :                         const Clef* c = toClef(clefSeg->element(track));
    1917         6815 :                         if (c && sys && sys->staff(staffIdx)->show()) {
    1918         6578 :                             isFirstClef = false;
    1919              :                         }
    1920              :                     }
    1921              :                 }
    1922        13305 :                 if (isFirstKeySig && searchMeasure->tick() >= keySigTick) {
    1923        10098 :                     const Segment* ksSeg = searchMeasure->findSegment(SegmentType::KeySig, searchMeasure->tick());
    1924        10098 :                     if (ksSeg && ksSeg->enabled()) {
    1925         6689 :                         const KeySig* ks = toKeySig(ksSeg->element(track));
    1926         6689 :                         if (ks && sys && sys->staff(staffIdx)->show()) {
    1927         6452 :                             isFirstKeySig = false;
    1928              :                         }
    1929              :                     }
    1930              :                 }
    1931        13305 :                 searchMeasure = searchMeasure->nextMeasureMM();
    1932              :             }
    1933              :         }
    1934              : 
    1935        17654 :         cSegment = addHeaderClef(m, isFirstSystem || isFirstClef, staff, ctx);
    1936              : 
    1937        17654 :         kSegment = addHeaderKeySig(m, isFirstSystem || isFirstKeySig, staff, ctx);
    1938              : 
    1939        17654 :         ++staffIdx;
    1940              :     }
    1941        11459 :     if (cSegment) {
    1942        11447 :         cSegment->createShapes();
    1943              :     }
    1944        11459 :     if (kSegment) {
    1945        11257 :         kSegment->createShapes();
    1946              :     }
    1947              : 
    1948        11459 :     MeasureLayout::createSystemBeginBarLine(m, ctx);
    1949              : 
    1950        11459 :     m->checkHeader();
    1951        11459 : }
    1952              : 
    1953          752 : void MeasureLayout::removeSystemHeader(Measure* m)
    1954              : {
    1955          752 :     if (!m->header()) {
    1956            0 :         return;
    1957              :     }
    1958         2659 :     for (Segment* seg = m->first(); seg; seg = seg->next()) {
    1959         2659 :         if (seg->isKeySigType()) {
    1960          749 :             bool keySigChangeHappensHere = false;
    1961         2013 :             for (Staff* staff : m->score()->staves()) {
    1962         1269 :                 if (staff->keyList()->count(m->tick().ticks()) > 0) {
    1963            5 :                     keySigChangeHappensHere = true;
    1964            5 :                     break;
    1965              :                 }
    1966              :             }
    1967          749 :             if (seg->header() && !keySigChangeHappensHere) {
    1968          744 :                 seg->setEnabled(false);
    1969              :             }
    1970              :         }
    1971         2659 :         if (!seg->header()) {
    1972          752 :             break;
    1973              :         }
    1974         1907 :         if (!seg->isKeySigType()) {
    1975         1158 :             seg->setEnabled(false);
    1976              :         }
    1977              :     }
    1978          752 :     m->setHeader(false);
    1979              : }
    1980              : 
    1981        34955 : void MeasureLayout::addSystemTrailer(Measure* m, Measure* nm, LayoutContext& ctx)
    1982              : {
    1983        34955 :     const size_t nstaves = ctx.dom().nstaves();
    1984        34955 :     bool systemBreakHideCourtesy = false;
    1985        34955 :     if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
    1986          101 :         systemBreakHideCourtesy = !sectionBreakElement->showCourtesy();
    1987              :     }
    1988              : 
    1989              :     // locate a time sig. in the next measure and, if found,
    1990              :     // check if it has court. sig. turned off
    1991        34955 :     if (nm && ctx.conf().styleB(Sid::genCourtesyTimesig) && !systemBreakHideCourtesy && !ctx.conf().isFloatMode()) {
    1992        30791 :         setCourtesyTimeSig(m, nm->tick(), m->endTick(), SegmentType::TimeSigAnnounce, ctx);
    1993              :     }
    1994              : 
    1995              :     // courtesy key signatures, clefs
    1996        34955 :     if (nm && ctx.conf().styleB(Sid::genCourtesyKeysig) && !systemBreakHideCourtesy) {
    1997        30917 :         setCourtesyKeySig(m, nm->tick(), m->endTick(), SegmentType::KeySigAnnounce, ctx);
    1998              :     }
    1999              : 
    2000        34955 :     Segment* courtesyClefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
    2001        34955 :     if (courtesyClefSeg) {
    2002          723 :         for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
    2003          423 :             const track_idx_t track = staffIdx * VOICES;
    2004              : 
    2005          423 :             Clef* courtesyClef = toClef(courtesyClefSeg->element(track));
    2006          423 :             if (courtesyClef) {
    2007          319 :                 courtesyClef->setSmall(true);
    2008          319 :                 courtesyClef->setIsTrailer(true);
    2009              :             }
    2010              :         }
    2011              :     }
    2012        34955 :     if (courtesyClefSeg) {
    2013          300 :         courtesyClefSeg->createShapes();
    2014              :     }
    2015              : 
    2016        34955 :     m->checkTrailer();
    2017        34955 : }
    2018              : 
    2019         1090 : void MeasureLayout::removeSystemTrailer(Measure* m, LayoutContext& ctx)
    2020              : {
    2021         2606 :     for (Segment* seg = m->last(); seg != m->first(); seg = seg->prev()) {
    2022         2208 :         if (seg->isChordRestType()) {
    2023          692 :             break;
    2024              :         }
    2025              : 
    2026         1516 :         if (seg->isClefType()) {
    2027          110 :             for (EngravingItem* el : seg->elist()) {
    2028           96 :                 if (!el) {
    2029           80 :                     continue;
    2030              :                 }
    2031           16 :                 Clef* clef = toClef(el);
    2032           16 :                 clef->setIsTrailer(false);
    2033           16 :                 TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
    2034              :             }
    2035           14 :             seg->createShapes();
    2036              :         }
    2037              : 
    2038         1516 :         if (seg->isTimeTickType() || !seg->trailer()) {
    2039         1084 :             continue;
    2040              :         }
    2041              : 
    2042          432 :         if (seg->enabled()) {
    2043          430 :             seg->setEnabled(false);
    2044          430 :             seg->setTrailer(false);
    2045              :         }
    2046              :     }
    2047         1090 :     m->setTrailer(false);
    2048         1090 : }
    2049              : 
    2050        25855 : void MeasureLayout::createSystemBeginBarLine(Measure* m, LayoutContext& ctx)
    2051              : {
    2052        25855 :     if (!m->system()) {
    2053            0 :         return;
    2054              :     }
    2055        25855 :     Segment* s  = m->findSegment(SegmentType::BeginBarLine, m->tick());
    2056        25855 :     size_t n = 0;
    2057        25855 :     if (m->system()) {
    2058        65291 :         for (SysStaff* sysStaff : m->system()->staves()) {
    2059        39436 :             if (sysStaff->show()) {
    2060        38855 :                 ++n;
    2061              :             }
    2062              :         }
    2063              :     }
    2064         7673 :     if ((n > 1 && ctx.conf().styleB(Sid::startBarlineMultiple))
    2065        33528 :         || (n == 1 && (ctx.conf().styleB(Sid::startBarlineSingle) || m->system()->brackets().size()))) {
    2066         7706 :         if (!s) {
    2067         1277 :             s = Factory::createSegment(m, SegmentType::BeginBarLine, Fraction(0, 1));
    2068         1277 :             m->add(s);
    2069              :         }
    2070        28764 :         for (track_idx_t track = 0; track < ctx.dom().ntracks(); track += VOICES) {
    2071        21058 :             BarLine* bl = toBarLine(s->element(track));
    2072        21058 :             if (!bl) {
    2073         3484 :                 bl = Factory::createBarLine(s);
    2074         3484 :                 bl->setTrack(track);
    2075         3484 :                 bl->setGenerated(true);
    2076         3484 :                 bl->setBarLineType(BarLineType::NORMAL);
    2077         3484 :                 bl->setSpanStaff(true);
    2078         3484 :                 s->add(bl);
    2079              :             }
    2080              : 
    2081        21058 :             TLayout::layoutBarLine(bl, bl->mutldata(), ctx);
    2082              :         }
    2083         7706 :         s->createShapes();
    2084         7706 :         s->setEnabled(true);
    2085         7706 :         s->setHeader(true);
    2086         7706 :         m->setHeader(true);
    2087        18149 :     } else if (s) {
    2088           73 :         s->setEnabled(false);
    2089              :     }
    2090              : }
    2091              : 
    2092            0 : void MeasureLayout::stretchMeasureInPracticeMode(Measure* m, double targetWidth, LayoutContext& ctx)
    2093              : {
    2094            0 :     Measure::LayoutData* ldata = m->mutldata();
    2095            0 :     ldata->setWidth(targetWidth);
    2096              : 
    2097              :     //---------------------------------------------------
    2098              :     //    compute stretch
    2099              :     //---------------------------------------------------
    2100              : 
    2101            0 :     std::multimap<double, Segment*> springs;
    2102              : 
    2103            0 :     Segment* seg = m->first();
    2104            0 :     while (seg && !seg->enabled()) {
    2105            0 :         seg = seg->next();
    2106              :     }
    2107            0 :     double minimumWidth = seg ? seg->x() : 0.0;
    2108            0 :     for (Segment& s : m->segments()) {
    2109            0 :         s.setStretch(1);
    2110              : 
    2111              : //        if (!s.enabled() || !s.visible())
    2112              : //            ;continue;
    2113            0 :         Fraction t = s.ticks();
    2114            0 :         if (t.isNotZero()) {
    2115            0 :             springs.insert(std::pair<double, Segment*>(0, &s));
    2116              :         }
    2117            0 :         minimumWidth += s.width() + s.spacing();
    2118              :     }
    2119              : 
    2120              :     //---------------------------------------------------
    2121              :     //    compute 1/Force for a given Extend
    2122              :     //---------------------------------------------------
    2123              : 
    2124            0 :     if (targetWidth > minimumWidth) {
    2125            0 :         double chordRestSegmentsWidth{ 0 };
    2126            0 :         for (auto i = springs.begin(); i != springs.end(); i++) {
    2127            0 :             chordRestSegmentsWidth += i->second->width() + i->second->spacing();
    2128              :         }
    2129              : 
    2130            0 :         double stretch = 1 + (targetWidth - minimumWidth) / chordRestSegmentsWidth;
    2131              : 
    2132              :         //---------------------------------------------------
    2133              :         //    distribute stretch to segments
    2134              :         //---------------------------------------------------
    2135              : 
    2136            0 :         for (auto& i : springs) {
    2137            0 :             i.second->setStretch(stretch);
    2138              :         }
    2139              : 
    2140              :         //---------------------------------------------------
    2141              :         //    move segments to final position
    2142              :         //---------------------------------------------------
    2143              : 
    2144            0 :         Segment* s = m->first();
    2145            0 :         while (s && !s->enabled()) {
    2146            0 :             s = s->next();
    2147              :         }
    2148              : 
    2149            0 :         double x = s ? s->pos().x() : 0.0;
    2150            0 :         while (s) {
    2151              : //            if (!s->enabled() || !s->visible()) {
    2152              : //                s = s->nextEnabled();
    2153              : //                continue;
    2154              : //            }
    2155              : 
    2156            0 :             double spacing = s->spacing();
    2157            0 :             double widthWithoutSpacing = s->width() - spacing;
    2158            0 :             double segmentStretch = s->stretch();
    2159            0 :             x += spacing * (muse::RealIsNull(segmentStretch) ? 1 : segmentStretch);
    2160            0 :             s->mutldata()->setPosX(x);
    2161            0 :             x += widthWithoutSpacing * (muse::RealIsNull(segmentStretch) ? 1 : segmentStretch);
    2162            0 :             s = s->nextEnabled();
    2163              :         }
    2164              :     }
    2165              : 
    2166              :     //---------------------------------------------------
    2167              :     //    layout individual elements
    2168              :     //---------------------------------------------------
    2169              : 
    2170            0 :     for (Segment& s : m->segments()) {
    2171            0 :         if (!s.enabled()) {
    2172            0 :             continue;
    2173              :         }
    2174              :         // After the rest of the spacing is calculated we position grace-notes-after.
    2175            0 :         ChordLayout::repositionGraceNotesAfter(&s, ctx.dom().ntracks());
    2176            0 :         for (EngravingItem* e : s.elist()) {
    2177            0 :             if (!e) {
    2178            0 :                 continue;
    2179              :             }
    2180            0 :             ElementType t = e->type();
    2181            0 :             staff_idx_t staffIdx = e->staffIdx();
    2182            0 :             if (t == ElementType::MEASURE_REPEAT || (t == ElementType::REST && (m->isMMRest() || toRest(e)->isFullMeasureRest()))) {
    2183              :                 //
    2184              :                 // element has to be centered in free space
    2185              :                 //    x1 - left measure position of free space
    2186              :                 //    x2 - right measure position of free space
    2187              : 
    2188              :                 Segment* s1;
    2189            0 :                 for (s1 = s.prev(); s1 && !s1->enabled(); s1 = s1->prev()) {
    2190              :                 }
    2191              :                 Segment* s2;
    2192            0 :                 for (s2 = s.next(); s2; s2 = s2->next()) {
    2193            0 :                     if (s2->enabled() && !s2->isChordRestType() && s2->element(staffIdx * VOICES)) {
    2194            0 :                         break;
    2195              :                     }
    2196              :                 }
    2197            0 :                 double x1 = s1 ? s1->x() + s1->minRight() : 0;
    2198            0 :                 double x2 = s2 ? s2->x() - s2->minLeft() : targetWidth;
    2199              : 
    2200            0 :                 if (m->isMMRest()) {
    2201            0 :                     MMRest* mmrest = toMMRest(e);
    2202              :                     //
    2203              :                     // center multi measure rest
    2204              :                     //
    2205            0 :                     double d = ctx.conf().styleAbsolute(Sid::multiMeasureRestMargin);
    2206            0 :                     double w = x2 - x1 - 2 * d;
    2207              : 
    2208            0 :                     mmrest->mutldata()->restWidth = w;
    2209            0 :                     TLayout::layoutMMRest(mmrest, mmrest->mutldata(), ctx);
    2210            0 :                     e->setPos(x1 - s.x() + d, e->staff()->staffHeight() * .5);   // center vertically in measure
    2211            0 :                     s.createShape(staffIdx);
    2212              :                 } else { // if (rest->isFullMeasureRest()) {
    2213              :                     //
    2214              :                     // center full measure rest
    2215              :                     //
    2216            0 :                     e->mutldata()->setPosX((x2 - x1 - e->width()) * .5 + x1 - s.x() - e->ldata()->bbox().x());
    2217            0 :                     s.createShape(staffIdx);  // DEBUG
    2218              :                 }
    2219            0 :             } else if (t == ElementType::REST) {
    2220            0 :                 e->mutldata()->setPosX(0);
    2221            0 :             } else if (t == ElementType::CHORD) {
    2222            0 :                 Chord* c = toChord(e);
    2223            0 :                 if (c->tremoloSingleChord()) {
    2224            0 :                     TremoloLayout::layout(c->tremoloSingleChord(), ctx);
    2225            0 :                 } else if (c->tremoloTwoChord()) {
    2226            0 :                     TremoloTwoChord* tr = c->tremoloTwoChord();
    2227            0 :                     Chord* c1 = tr->chord1();
    2228            0 :                     Chord* c2 = tr->chord2();
    2229            0 :                     if (c1 && !c1->staffMove() && c2 && !c2->staffMove()) {
    2230            0 :                         TremoloLayout::layout(tr, ctx);
    2231              :                     }
    2232              :                 }
    2233            0 :             } else if (t == ElementType::BAR_LINE) {
    2234            0 :                 e->mutldata()->setPosY(0.0);
    2235              :                 // for end barlines, x position was set in createEndBarLines
    2236            0 :                 if (s.segmentType() != SegmentType::EndBarLine) {
    2237            0 :                     e->mutldata()->setPosX(0.0);
    2238              :                 }
    2239              :             }
    2240              :         }
    2241              :     }
    2242            0 : }
    2243              : 
    2244        31954 : void MeasureLayout::layoutTimeTickAnchors(Measure* m, LayoutContext& ctx)
    2245              : {
    2246        31954 :     bool darker = true;
    2247       153228 :     for (Segment& segment : m->segments()) {
    2248       121274 :         if (!segment.isTimeTickType()) {
    2249       120781 :             continue;
    2250              :         }
    2251              : 
    2252          501 :         Segment* refCRSeg = m->findSegmentR(SegmentType::ChordRest, segment.rtick());
    2253          501 :         if (!(refCRSeg && refCRSeg->isActive())) {
    2254          405 :             refCRSeg = segment.prevActive();
    2255          408 :             while (refCRSeg && !refCRSeg->isChordRestType()) {
    2256            3 :                 refCRSeg = refCRSeg->prevActive();
    2257              :             }
    2258              :         }
    2259              : 
    2260          501 :         if (!refCRSeg || refCRSeg->ticks().isZero()) {
    2261            8 :             continue;
    2262              :         }
    2263              : 
    2264          493 :         Fraction refSegDuration = refCRSeg->ticks();
    2265          493 :         Fraction thisDuration = segment.ticks();
    2266          493 :         Fraction relativeTick = segment.rtick() - refCRSeg->rtick();
    2267              : 
    2268          493 :         Segment* nextSeg = m->findSegmentR(SegmentType::ChordRest, refCRSeg->rtick() + refCRSeg->ticks());
    2269          493 :         if (!(nextSeg && nextSeg->isActive())) {
    2270          425 :             nextSeg = m->findSegmentR(SegmentType::BarLineTypes, refCRSeg->rtick() + refCRSeg->ticks());
    2271              :         }
    2272          493 :         double width = nextSeg ? nextSeg->x() - refCRSeg->x() : refCRSeg->width();
    2273              : 
    2274          493 :         double relativeX = width * (relativeTick.toDouble() / refCRSeg->ticks().toDouble());
    2275          493 :         double relativeWidth = width * (thisDuration.toDouble() / refSegDuration.toDouble());
    2276              : 
    2277          493 :         segment.mutldata()->setPosX(refCRSeg->x() + relativeX);
    2278          493 :         segment.setWidth(relativeWidth);
    2279              : 
    2280         3449 :         for (EngravingItem* item : segment.elist()) {
    2281         2956 :             if (item) {
    2282          498 :                 TLayout::layoutItem(item, ctx);
    2283          498 :                 toTimeTickAnchor(item)->mutldata()->setDarker(darker);
    2284              :             }
    2285              :         }
    2286          493 :         darker = !darker;
    2287              :     }
    2288        31954 : }
    2289              : 
    2290              : //---------------------------------------------------------
    2291              : //   layoutPartialWidth
    2292              : ///   Layout staff lines for the specified width only, aligned
    2293              : ///   to the left or right of the measure
    2294              : //---------------------------------------------------------
    2295              : 
    2296            0 : void MeasureLayout::layoutPartialWidth(StaffLines* lines, LayoutContext& ctx, double w, double wPartial, bool alignRight)
    2297              : {
    2298            0 :     StaffLines::LayoutData* ldata = lines->mutldata();
    2299            0 :     const Staff* s = lines->staff();
    2300            0 :     double _spatium = lines->spatium();
    2301            0 :     wPartial *= _spatium;
    2302            0 :     double dist     = _spatium;
    2303            0 :     lines->setPos(PointF(0.0, 0.0));
    2304              :     int _lines;
    2305            0 :     if (s) {
    2306            0 :         lines->mutldata()->setMag(s->staffMag(lines->measure()->tick()));
    2307            0 :         lines->setColor(s->color(lines->measure()->tick()));
    2308            0 :         const StaffType* st = s->staffType(lines->measure()->tick());
    2309            0 :         dist         *= st->lineDistance().val();
    2310            0 :         _lines        = st->lines();
    2311            0 :         lines->mutldata()->setPosY(lines->staffOffsetY());
    2312              :     } else {
    2313            0 :         _lines = 5;
    2314            0 :         lines->setColor(lines->configuration()->defaultColor());
    2315              :     }
    2316            0 :     lines->setLw(ctx.conf().styleS(Sid::staffLineWidth).val() * _spatium);
    2317            0 :     double x1 = lines->pos().x();
    2318            0 :     double x2 = x1 + w;
    2319            0 :     double y  = lines->pos().y();
    2320            0 :     ldata->setBbox(x1, -lines->lw() * .5 + y, w, (_lines - 1) * dist + lines->lw());
    2321              : 
    2322            0 :     if (_lines == 1) {
    2323            0 :         double extraSize = _spatium;
    2324            0 :         ldata->setBbox(ldata->bbox().adjusted(0, -extraSize, 0, extraSize));
    2325              :     }
    2326              : 
    2327            0 :     std::vector<LineF> ll;
    2328            0 :     for (int i = 0; i < _lines; ++i) {
    2329            0 :         if (alignRight) {
    2330            0 :             ll.push_back(LineF(x2 - wPartial, y, x2, y));
    2331              :         } else {
    2332            0 :             ll.push_back(LineF(x1, y, x1 + wPartial, y));
    2333              :         }
    2334            0 :         y += dist;
    2335              :     }
    2336            0 :     lines->setLines(ll);
    2337            0 : }
    2338              : 
    2339        23147 : void MeasureLayout::updateKeySignatures(const Measure* measure, LayoutContext& ctx)
    2340              : {
    2341        23147 :     Measure* prevMeasure = measure->prevMeasure();
    2342        23147 :     if (!prevMeasure || !prevMeasure->repeatEnd()) {
    2343        22862 :         return;
    2344              :     }
    2345         1156 :     for (const Segment& seg : measure->segments()) {
    2346          871 :         if (!seg.isType(SegmentType::KeySigTypes)) {
    2347          863 :             continue;
    2348              :         }
    2349              : 
    2350           68 :         for (EngravingItem* el : seg.elist()) {
    2351           60 :             if (!el) {
    2352           45 :                 continue;
    2353              :             }
    2354              : 
    2355           15 :             KeySig* ks = toKeySig(el);
    2356              : 
    2357           15 :             TLayout::layoutKeySig(ks, ks->mutldata(), ctx.conf());
    2358              :         }
    2359              :     }
    2360              : }
        

Generated by: LCOV version 2.0-1