LCOV - code coverage report
Current view: top level - src/engraving/dom - measure.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 55.9 % 1861 1040
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) 2021 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              : 
      23              : /**
      24              :  \file
      25              :  Implementation of most part of class Measure.
      26              : */
      27              : 
      28              : #include "measure.h"
      29              : 
      30              : #include "../editing/editstaffbrackets.h"
      31              : #include "../editing/editclef.h"
      32              : #include "../editing/editkeysig.h"
      33              : #include "../editing/editmeasures.h"
      34              : #include "../editing/editmeasurerepeat.h"
      35              : #include "../editing/editstaff.h"
      36              : #include "../editing/editsystemlocks.h"
      37              : #include "../editing/edittimesig.h"
      38              : #include "../editing/inserttime.h"
      39              : #include "../editing/navigation.h"
      40              : #include "../editing/transaction/transaction.h"
      41              : 
      42              : #include "accidental.h"
      43              : #include "actionicon.h"
      44              : #include "anchors.h"
      45              : #include "barline.h"
      46              : #include "beam.h"
      47              : #include "bracket.h"
      48              : #include "bracketitem.h"
      49              : #include "chord.h"
      50              : #include "clef.h"
      51              : #include "durationelement.h"
      52              : #include "factory.h"
      53              : #include "hook.h"
      54              : #include "key.h"
      55              : #include "keysig.h"
      56              : #include "linkedobjects.h"
      57              : #include "marker.h"
      58              : #include "masterscore.h"
      59              : #include "measure.h"
      60              : #include "measurenumber.h"
      61              : #include "measurerepeat.h"
      62              : #include "mmrestrange.h"
      63              : #include "note.h"
      64              : #include "page.h"
      65              : #include "part.h"
      66              : #include "pitchspelling.h"
      67              : #include "playcounttext.h"
      68              : #include "rest.h"
      69              : #include "score.h"
      70              : #include "segment.h"
      71              : #include "select.h"
      72              : #include "sig.h"
      73              : #include "spacer.h"
      74              : #include "staff.h"
      75              : #include "stafflines.h"
      76              : #include "stafftype.h"
      77              : #include "stafftypechange.h"
      78              : #include "stem.h"
      79              : #include "system.h"
      80              : #include "tie.h"
      81              : #include "tiemap.h"
      82              : #include "timesig.h"
      83              : #include "tremolosinglechord.h"
      84              : #include "tremolotwochord.h"
      85              : #include "tuplet.h"
      86              : #include "tupletmap.h"
      87              : #include "utils.h"
      88              : 
      89              : #ifndef ENGRAVING_NO_ACCESSIBILITY
      90              : #include "accessibility/accessibleitem.h"
      91              : #endif
      92              : 
      93              : #include "log.h"
      94              : 
      95              : using namespace mu;
      96              : using namespace mu::engraving;
      97              : 
      98              : namespace mu::engraving {
      99              : //---------------------------------------------------------
     100              : //   MStaff
     101              : ///   Per staff values of measure.
     102              : //---------------------------------------------------------
     103              : 
     104        22937 : MStaff::~MStaff()
     105              : {
     106        22937 :     delete m_measureNumber;
     107        22937 :     delete m_mmRangeText;
     108        22937 :     delete m_lines;
     109        22937 :     delete m_vspacerUp;
     110        22937 :     delete m_vspacerDown;
     111        22937 : }
     112              : 
     113            0 : MStaff::MStaff(const MStaff& m)
     114              : {
     115            0 :     m_measureNumber    = 0;
     116            0 :     m_mmRangeText = 0;
     117            0 :     m_lines     = Factory::copyStaffLines(*m.m_lines);
     118            0 :     m_hasVoices = m.m_hasVoices;
     119            0 :     m_vspacerUp = 0;
     120            0 :     m_vspacerDown = 0;
     121            0 :     m_hideIfEmpty = m.m_hideIfEmpty;
     122            0 :     m_visible   = m.m_visible;
     123            0 :     m_stemless  = m.m_stemless;
     124              : #ifndef NDEBUG
     125            0 :     m_corrupted = m.m_corrupted;
     126              : #endif
     127            0 :     m_measureRepeatCount = 0;
     128            0 : }
     129              : 
     130              : //---------------------------------------------------------
     131              : //   MStaff::setScore
     132              : //---------------------------------------------------------
     133              : 
     134            0 : void MStaff::setScore(Score* score)
     135              : {
     136            0 :     if (m_lines) {
     137            0 :         m_lines->setScore(score);
     138              :     }
     139            0 :     if (m_vspacerUp) {
     140            0 :         m_vspacerUp->setScore(score);
     141              :     }
     142            0 :     if (m_vspacerDown) {
     143            0 :         m_vspacerDown->setScore(score);
     144              :     }
     145            0 :     if (m_measureNumber) {
     146            0 :         m_measureNumber->setScore(score);
     147              :     }
     148            0 :     if (m_mmRangeText) {
     149            0 :         m_mmRangeText->setScore(score);
     150              :     }
     151            0 : }
     152              : 
     153              : //---------------------------------------------------------
     154              : //   setTrack
     155              : //---------------------------------------------------------
     156              : 
     157         2538 : void MStaff::setTrack(track_idx_t track)
     158              : {
     159         2538 :     if (m_lines) {
     160         2538 :         m_lines->setTrack(track);
     161              :     }
     162         2538 :     if (m_vspacerUp) {
     163            0 :         m_vspacerUp->setTrack(track);
     164              :     }
     165         2538 :     if (m_vspacerDown) {
     166            0 :         m_vspacerDown->setTrack(track);
     167              :     }
     168         2538 :     if (m_measureNumber) {
     169           69 :         m_measureNumber->setTrack(track);
     170              :     }
     171         2538 :     if (m_mmRangeText) {
     172            0 :         m_mmRangeText->setTrack(track);
     173              :     }
     174         2538 : }
     175              : 
     176              : //---------------------------------------------------------
     177              : //   Measure
     178              : //---------------------------------------------------------
     179              : 
     180        17166 : Measure::Measure(Score* parent)
     181        17166 :     : MeasureBase(ElementType::MEASURE, parent), m_timesig(4, 4)
     182              : {
     183        17166 :     setTicks(Fraction(4, 4));
     184        17166 :     m_repeatCount = 2;
     185              : 
     186        17166 :     size_t n = score()->nstaves();
     187        17166 :     m_mstaves.reserve(n);
     188        41226 :     for (staff_idx_t staffIdx = 0; staffIdx < n; ++staffIdx) {
     189        24060 :         MStaff* ms = new MStaff;
     190        24060 :         Staff* staff = score()->staff(staffIdx);
     191        24060 :         ms->setLines(Factory::createStaffLines(this));
     192        24060 :         ms->lines()->setTrack(staffIdx * VOICES);
     193        24060 :         ms->lines()->setVisible(!staff->isLinesInvisible(tick()));
     194        24060 :         m_mstaves.push_back(ms);
     195              :     }
     196        17166 :     setExcludeFromNumbering(false);
     197        17166 :     m_measureNumberMode     = MeasureNumberMode::AUTO;
     198        17166 :     m_userStretch           = 1.0;
     199        17166 :     m_breakMultiMeasureRest = false;
     200        17166 :     m_mmRest                = nullptr;
     201        17166 :     m_mmRestCount           = 0;
     202        17166 :     setFlag(ElementFlag::MOVABLE, false);
     203        17166 : }
     204              : 
     205              : //---------------------------------------------------------
     206              : //   measure
     207              : //---------------------------------------------------------
     208              : 
     209            0 : Measure::Measure(const Measure& m)
     210            0 :     : MeasureBase(m)
     211              : {
     212            0 :     m_segments    = m.m_segments.clone();
     213            0 :     m_timesig     = m.m_timesig;
     214            0 :     m_len         = m.m_len;
     215            0 :     m_repeatCount = m.m_repeatCount;
     216            0 :     m_measureNumber = m.m_measureNumber;
     217            0 :     m_measureNumberOffset = m.m_measureNumberOffset;
     218            0 :     m_measureNumberMode = m.m_measureNumberMode;
     219            0 :     m_userStretch = m.m_userStretch;
     220              : 
     221            0 :     m_mstaves.reserve(m.m_mstaves.size());
     222            0 :     for (MStaff* ms : m.m_mstaves) {
     223            0 :         m_mstaves.push_back(new MStaff(*ms));
     224              :     }
     225              : 
     226            0 :     m_breakMultiMeasureRest = m.m_breakMultiMeasureRest;
     227            0 :     m_mmRest                = m.m_mmRest;
     228            0 :     m_mmRestCount           = m.m_mmRestCount;
     229            0 :     m_playbackCount         = m.m_playbackCount;
     230            0 : }
     231              : 
     232              : //---------------------------------------------------------
     233              : //   createStaves
     234              : //---------------------------------------------------------
     235              : 
     236          887 : void Measure::createStaves(staff_idx_t staffIdx)
     237              : {
     238          887 :     for (staff_idx_t n = m_mstaves.size(); n <= staffIdx; ++n) {
     239            0 :         Staff* staff = score()->staff(n);
     240            0 :         MStaff* s    = new MStaff;
     241            0 :         s->setLines(Factory::createStaffLines(this));
     242            0 :         s->lines()->setTrack(n * VOICES);
     243            0 :         s->lines()->setVisible(!staff->isLinesInvisible(tick()));
     244            0 :         m_mstaves.push_back(s);
     245              :     }
     246          887 : }
     247              : 
     248              : //---------------------------------------------------------
     249              : //   setScore
     250              : //---------------------------------------------------------
     251              : 
     252            0 : void Measure::setScore(Score* score)
     253              : {
     254            0 :     MeasureBase::setScore(score);
     255            0 :     for (Segment* s = first(); s; s = s->next()) {
     256            0 :         s->setScore(score);
     257              :     }
     258            0 : }
     259              : 
     260      1039696 : MStaff* Measure::mstaff(staff_idx_t staffIndex) const
     261              : {
     262      1039696 :     if (staffIndex < m_mstaves.size()) {
     263      1038075 :         return m_mstaves[staffIndex];
     264              :     }
     265              : 
     266         1621 :     return nullptr;
     267              : }
     268              : 
     269       223137 : bool Measure::hasVoices(staff_idx_t staffIdx) const
     270              : {
     271       223137 :     MStaff* staff = mstaff(staffIdx);
     272       223137 :     return staff ? staff->hasVoices() : false;
     273              : }
     274              : 
     275         5284 : void Measure::setHasVoices(staff_idx_t staffIdx, bool v)
     276              : {
     277         5284 :     MStaff* staff = mstaff(staffIdx);
     278              : 
     279         5284 :     if (staff) {
     280         3663 :         staff->setHasVoices(v);
     281              :     }
     282         5284 : }
     283              : 
     284       507618 : StaffLines* Measure::staffLines(staff_idx_t staffIdx) const
     285              : {
     286       507618 :     MStaff* staff = mstaff(staffIdx);
     287              : 
     288       507618 :     return staff ? staff->lines() : nullptr;
     289              : }
     290              : 
     291       143961 : Spacer* Measure::vspacerDown(staff_idx_t staffIdx) const
     292              : {
     293       143961 :     MStaff* staff = mstaff(staffIdx);
     294              : 
     295       143961 :     return staff ? staff->vspacerDown() : nullptr;
     296              : }
     297              : 
     298       136105 : Spacer* Measure::vspacerUp(staff_idx_t staffIdx) const
     299              : {
     300       136105 :     MStaff* staff = mstaff(staffIdx);
     301              : 
     302       136105 :     return staff ? staff->vspacerUp() : nullptr;
     303              : }
     304              : 
     305           21 : void Measure::setStaffVisible(staff_idx_t staffIdx, bool visible)
     306              : {
     307           21 :     MStaff* staff = mstaff(staffIdx);
     308              : 
     309           21 :     if (staff) {
     310           21 :         staff->setVisible(visible);
     311              :     }
     312           21 : }
     313              : 
     314          845 : void Measure::setStaffStemless(staff_idx_t staffIdx, bool stemless)
     315              : {
     316          845 :     MStaff* staff = mstaff(staffIdx);
     317              : 
     318          845 :     if (staff) {
     319          845 :         staff->setStemless(stemless);
     320              :     }
     321          845 : }
     322              : 
     323        22725 : AutoOnOff Measure::hideStaffIfEmpty(staff_idx_t staffIdx) const
     324              : {
     325        22725 :     MStaff* staff = mstaff(staffIdx);
     326              : 
     327        22725 :     return staff ? staff->hideIfEmpty() : AutoOnOff::AUTO;
     328              : }
     329              : 
     330            0 : void Measure::setHideStaffIfEmpty(staff_idx_t staffIdx, AutoOnOff hideIfEmpty)
     331              : {
     332            0 :     MStaff* staff = mstaff(staffIdx);
     333            0 :     IF_ASSERT_FAILED(staff) {
     334            0 :         return;
     335              :     }
     336              : 
     337            0 :     staff->setHideIfEmpty(hideIfEmpty);
     338              : }
     339              : 
     340            0 : void Measure::setMMRangeText(staff_idx_t staffIdx, MMRestRange* t)
     341              : {
     342            0 :     m_mstaves[staffIdx]->setMMRangeText(t);
     343            0 : }
     344              : 
     345        45859 : MMRestRange* Measure::mmRangeText(staff_idx_t staffIdx) const
     346              : {
     347        45859 :     return m_mstaves[staffIdx]->mmRangeText();
     348              : }
     349              : 
     350              : //---------------------------------------------------------
     351              : //   Measure
     352              : //---------------------------------------------------------
     353              : 
     354        32018 : Measure::~Measure()
     355              : {
     356        76861 :     for (Segment* s = first(); s;) {
     357        60852 :         Segment* ns = s->next();
     358        60852 :         delete s;
     359        60852 :         s = ns;
     360              :     }
     361        16009 :     muse::DeleteAll(m_mstaves);
     362        32018 : }
     363              : 
     364              : #ifndef ENGRAVING_NO_ACCESSIBILITY
     365            0 : AccessibleItemPtr Measure::createAccessible()
     366              : {
     367            0 :     return std::make_shared<AccessibleItem>(this, AccessibleItem::Group);
     368              : }
     369              : 
     370              : #endif
     371              : 
     372              : //---------------------------------------------------------
     373              : //   findAccidental
     374              : ///   return current accidental value at note position
     375              : //---------------------------------------------------------
     376              : 
     377          265 : AccidentalVal Measure::findAccidental(const Note* note) const
     378              : {
     379          265 :     const Chord* chord = note->chord();
     380          265 :     const Staff* vStaff = chord->score()->staff(chord->vStaffIdx());
     381          265 :     AccidentalState tversatz;    // state of already set accidentals for this measure
     382          265 :     tversatz.init(vStaff->keySigEvent(tick()));
     383              : 
     384          265 :     const TrackRange trackRange = vStaff->part()->trackRange();
     385          265 :     track_idx_t mainTrack = chord->vStaffIdx() * VOICES;
     386              : 
     387          958 :     for (const Segment* segment = first(); segment; segment = segment->next()) {
     388          956 :         if (segment->isKeySigType()) {
     389          177 :             const KeySig* ks = toKeySig(segment->element(mainTrack));
     390          177 :             if (!ks) {
     391            0 :                 continue;
     392              :             }
     393          177 :             tversatz.init(vStaff->keySigEvent(segment->tick()));
     394          779 :         } else if (segment->segmentType() == SegmentType::ChordRest) {
     395         1988 :             for (track_idx_t track = trackRange.startTrack; track < trackRange.endTrack; ++track) {
     396         1674 :                 const EngravingItem* e = segment->element(track);
     397         1674 :                 if (!e || !e->isChord()) {
     398         1137 :                     continue;
     399              :                 }
     400          537 :                 const Chord* crd = toChord(e);
     401          757 :                 for (const Chord* chord1 : crd->graceNotes()) {
     402          374 :                     if (chord1->vStaffIdx() != chord->vStaffIdx()) {
     403            0 :                         continue;
     404              :                     }
     405          604 :                     for (const Note* note1 : chord1->notes()) {
     406          384 :                         if (note1->tieBack() && !note1->accidental()) {
     407            0 :                             continue;
     408              :                         }
     409              :                         //
     410              :                         // compute accidental
     411              :                         //
     412          384 :                         int tpc  = note1->tpc();
     413          384 :                         int line = absStep(tpc, note1->epitch());
     414              : 
     415          384 :                         if (note == note1) {
     416          154 :                             return tversatz.accidentalVal(line);
     417              :                         }
     418          230 :                         tversatz.setAccidentalVal(line, tpc2alter(tpc));
     419              :                     }
     420              :                 }
     421          383 :                 if (crd->vStaffIdx() != chord->vStaffIdx()) {
     422            6 :                     continue;
     423              :                 }
     424          707 :                 for (const Note* note1 : crd->notes()) {
     425          439 :                     if (note1->tieBack() && !note1->accidental()) {
     426           27 :                         continue;
     427              :                     }
     428              :                     //
     429              :                     // compute accidental
     430              :                     //
     431          412 :                     int tpc  = note1->tpc();
     432          412 :                     int line = absStep(tpc, note1->epitch());
     433              : 
     434          412 :                     if (note == note1) {
     435          109 :                         return tversatz.accidentalVal(line);
     436              :                     }
     437          303 :                     tversatz.setAccidentalVal(line, tpc2alter(tpc));
     438              :                 }
     439              :             }
     440              :         }
     441              :     }
     442            2 :     LOGD() << "Measure::findAccidental: note not found";
     443            2 :     return AccidentalVal::NATURAL;
     444              : }
     445              : 
     446              : //---------------------------------------------------------
     447              : //   findAccidental
     448              : ///   Compute accidental state at segment/staffIdx for
     449              : ///   relative staff line.
     450              : //---------------------------------------------------------
     451              : 
     452           82 : AccidentalVal Measure::findAccidental(const Segment* s, staff_idx_t staffIdx, int line, bool& error) const
     453              : {
     454           82 :     AccidentalState tversatz;    // state of already set accidentals for this measure
     455           82 :     const Staff* staff = score()->staff(staffIdx);
     456           82 :     tversatz.init(staff->keySigEvent(tick()));
     457              : 
     458           82 :     SegmentType st = SegmentType::ChordRest;
     459           82 :     const TrackRange trackRange = staff->part()->trackRange();
     460          123 :     for (const Segment* segment = first(st); segment; segment = segment->next(st)) {
     461          123 :         if (segment == s && staff->isPitchedStaff(tick())) {
     462           82 :             ClefType clef = staff->clef(s->tick());
     463           82 :             int l = relStep(line, clef);
     464           82 :             return tversatz.accidentalVal(l, error);
     465              :         }
     466          205 :         for (track_idx_t track = trackRange.startTrack; track < trackRange.endTrack; ++track) {
     467          164 :             const EngravingItem* e = segment->element(track);
     468          164 :             if (!e || !e->isChord()) {
     469          115 :                 continue;
     470              :             }
     471           49 :             const Chord* chord = toChord(e);
     472           49 :             for (const Chord* chord1 : chord->graceNotes()) {
     473            0 :                 if (chord1->vStaffIdx() != staffIdx) {
     474            0 :                     continue;
     475              :                 }
     476            0 :                 for (const Note* note : chord1->notes()) {
     477            0 :                     if (note->tieBack() && !note->accidental()) {
     478            0 :                         continue;
     479              :                     }
     480            0 :                     int tpc  = note->tpc();
     481            0 :                     int l    = absStep(tpc, note->epitch());
     482            0 :                     tversatz.setAccidentalVal(l, tpc2alter(tpc));
     483              :                 }
     484              :             }
     485           49 :             if (chord->vStaffIdx() != staffIdx) {
     486            0 :                 continue;
     487              :             }
     488          112 :             for (const Note* note : chord->notes()) {
     489           63 :                 if (note->tieBack() && !note->accidental()) {
     490            0 :                     continue;
     491              :                 }
     492           63 :                 int tpc    = note->tpc();
     493           63 :                 int l      = absStep(tpc, note->epitch());
     494           63 :                 tversatz.setAccidentalVal(l, tpc2alter(tpc));
     495              :             }
     496              :         }
     497              :     }
     498            0 :     LOGD() << "segment not found";
     499            0 :     return AccidentalVal::NATURAL;
     500              : }
     501              : 
     502              : //---------------------------------------------------------
     503              : //   tick2pos
     504              : ///    return x position for tick relative to System
     505              : //---------------------------------------------------------
     506              : 
     507            0 : double Measure::tick2pos(Fraction tck) const
     508              : {
     509            0 :     tck -= ticks();
     510            0 :     if (isMMRest()) {
     511            0 :         Segment* s = first(SegmentType::ChordRest);
     512            0 :         double x1   = s->x();
     513            0 :         double w    = width() - x1;
     514            0 :         return x1 + (tck.ticks() * w) / (ticks().ticks() * mmRestCount());
     515              :     }
     516              : 
     517              :     Segment* s;
     518            0 :     double x1  = 0;
     519            0 :     double x2  = 0;
     520            0 :     Fraction tick1 = Fraction(0, 1);
     521            0 :     Fraction tick2 = Fraction(0, 1);
     522            0 :     for (s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
     523            0 :         x2    = s->x();
     524            0 :         tick2 = s->rtick();
     525            0 :         if (tck == tick2) {
     526            0 :             return x2 + pos().x();
     527              :         }
     528            0 :         if (tck <= tick2) {
     529            0 :             break;
     530              :         }
     531            0 :         x1    = x2;
     532            0 :         tick1 = tick2;
     533              :     }
     534            0 :     if (s == 0) {
     535            0 :         x2    = width();
     536            0 :         tick2 = ticks();
     537              :     }
     538            0 :     double dx = x2 - x1;
     539            0 :     Fraction dt   = tick2 - tick1;
     540            0 :     x1      += dt.isZero() ? 0.0 : (dx * (tck.ticks() - tick1.ticks()) / dt.ticks());
     541            0 :     return x1 + pos().x();
     542              : }
     543              : 
     544              : //---------------------------------------------------------
     545              : //   showsMeasureNumberInAutoMode
     546              : ///    Whether the measure will show measure number(s) when MeasureNumberMode is set to AUTO
     547              : //---------------------------------------------------------
     548              : 
     549       142816 : bool Measure::showMeasureNumberInAutoMode() const
     550              : {
     551              :     // Check whether any measure number should be shown
     552       142816 :     if (!style().styleB(Sid::showMeasureNumber)) {
     553          912 :         return false;
     554              :     }
     555              : 
     556              :     // Measure numbers should not be shown on measures excluded from numbering.
     557       141904 :     if (excludeFromNumbering()) {
     558          156 :         return false;
     559              :     }
     560              : 
     561       141748 :     int interval = style().styleI(Sid::measureNumberInterval);
     562       141748 :     Measure* prevMeasure = this->prevMeasure();
     563              : 
     564              :     // Measure numbers should not show on first measure unless specified with Sid::showMeasureNumberOne
     565              :     // except, when showing numbers on each measure, and first measure is after anacrusis - then show always
     566       141748 :     if (isFirstInSection() || (prevMeasure->excludeFromNumbering() && prevMeasure->isFirstInSection() && interval != 1)) {
     567        18826 :         return style().styleB(Sid::showMeasureNumberOne);
     568              :     }
     569              : 
     570       122922 :     if (style().styleB(Sid::measureNumberSystem)) {
     571              :         // Show either if
     572              :         //   1) This is the first measure of the system OR
     573              :         //   2) The previous measure in the system is the first, and is excluded from numbering.
     574       242029 :         return (system() && isFirstInSystem())
     575       242029 :                || (prevMeasure && prevMeasure->excludeFromNumbering() && prevMeasure->system() && prevMeasure->isFirstInSystem());
     576              :     } else {
     577              :         // In the case of an interval, we should show the measure number either if:
     578              :         //   1) We should show them every measure
     579         1906 :         if (interval == 1) {
     580         1651 :             return true;
     581              :         }
     582              : 
     583              :         //   2) (measureNumber + 1) % interval == 0 (or 1 if measure number one is numbered.)
     584              :         // If measure number 1 is numbered, and the interval is let's say 5, then we should number #1, 6, 11, 16, etc.
     585              :         // If measure number 1 is not numbered, with the same interval (5), then we should number #5, 10, 15, 20, etc.
     586          255 :         return ((measureNumber() + 1) % interval) == (style().styleB(Sid::showMeasureNumberOne) ? 1 : 0);
     587              :     }
     588              : }
     589              : 
     590       142816 : bool Measure::showMeasureNumberOnStaff(staff_idx_t staffIdx) const
     591              : {
     592       142816 :     IF_ASSERT_FAILED(staffIdx < score()->nstaves()) {
     593            0 :         return false;
     594              :     }
     595              : 
     596       142816 :     return showMeasureNumber() && score()->staff(staffIdx)->shouldShowMeasureNumbers() && !score()->allStavesInvisible();
     597              : }
     598              : 
     599              : //---------------------------------------------------------
     600              : //   showsMeasureNumber
     601              : ///     Whether the Measure shows a MeasureNumber
     602              : //---------------------------------------------------------
     603              : 
     604       142816 : bool Measure::showMeasureNumber() const
     605              : {
     606       142816 :     switch (m_measureNumberMode) {
     607       142816 :     case MeasureNumberMode::AUTO:
     608       142816 :         return showMeasureNumberInAutoMode();
     609            0 :     case MeasureNumberMode::SHOW:
     610            0 :         return true;
     611            0 :     case MeasureNumberMode::HIDE:
     612            0 :         break;
     613              :     }
     614            0 :     return false;
     615              : }
     616              : 
     617              : //---------------------------------------------------------
     618              : //   findChord
     619              : ///   Search for chord at position \a tick in \a track
     620              : //---------------------------------------------------------
     621              : 
     622        12407 : Chord* Measure::findChord(Fraction t, track_idx_t track) const
     623              : {
     624        12407 :     t -= tick();
     625        33614 :     for (Segment* seg = last(); seg; seg = seg->prev()) {
     626        31127 :         if (seg->rtick() < t) {
     627         3914 :             return 0;
     628              :         }
     629        27213 :         if (seg->rtick() == t) {
     630        10280 :             EngravingItem* el = seg->element(track);
     631        10280 :             if (el && el->isChord()) {
     632         6006 :                 return toChord(el);
     633              :             }
     634              :         }
     635              :     }
     636         2487 :     return 0;
     637              : }
     638              : 
     639              : //---------------------------------------------------------
     640              : //   findChordRest
     641              : ///   Search for chord or rest at position \a tick at \a staff in \a voice.
     642              : //---------------------------------------------------------
     643              : 
     644          287 : ChordRest* Measure::findChordRest(Fraction t, track_idx_t track) const
     645              : {
     646          287 :     t -= tick();
     647          430 :     for (const Segment& seg : m_segments) {
     648          428 :         if (seg.rtick() > t) {
     649          285 :             return 0;
     650              :         }
     651          423 :         if (seg.rtick() == t) {
     652          370 :             EngravingItem* el = seg.element(track);
     653          370 :             if (el && el->isChordRest()) {
     654          280 :                 return toChordRest(el);
     655              :             }
     656              :         }
     657              :     }
     658            2 :     return 0;
     659              : }
     660              : 
     661              : //---------------------------------------------------------
     662              : //   tick2segment
     663              : //---------------------------------------------------------
     664              : 
     665          274 : Segment* Measure::tick2segment(const Fraction& _t, SegmentType st)
     666              : {
     667          274 :     Fraction t = _t - tick();
     668         1302 :     for (Segment& s : m_segments) {
     669         1302 :         if (s.rtick() == t) {
     670          306 :             if (s.segmentType() & st) {
     671          274 :                 return &s;
     672              :             }
     673              :         }
     674         1028 :         if (s.rtick() > t) {
     675            0 :             break;
     676              :         }
     677              :     }
     678            0 :     return 0;
     679              : }
     680              : 
     681              : //---------------------------------------------------------
     682              : //   findSegmentR
     683              : //    Search for a segment of type st at measure relative
     684              : //    position t.
     685              : //---------------------------------------------------------
     686              : 
     687      1079838 : Segment* Measure::findSegmentR(SegmentType st, const Fraction& t) const
     688              : {
     689              :     Segment* s;
     690      1079838 :     if (t > (ticks() * Fraction(1, 2))) {
     691              :         // search backwards
     692       576476 :         for (s = last(); s && s->rtick() > t; s = s->prev()) {
     693              :         }
     694       589646 :         while (s && s->prev() && s->prev()->rtick() == t) {
     695        19803 :             s = s->prev();
     696              :         }
     697              :     } else {
     698              :         // search forwards
     699       578712 :         for (s = first(); s && s->rtick() < t; s = s->next()) {
     700              :         }
     701              :     }
     702      2250068 :     for (; s && s->rtick() == t; s = s->next()) {
     703      1339189 :         if (s->segmentType() & st) {
     704       168959 :             return s;
     705              :         }
     706              :     }
     707       910879 :     return 0;
     708              : }
     709              : 
     710              : //---------------------------------------------------------
     711              : //   undoGetSegmentR
     712              : //---------------------------------------------------------
     713              : 
     714         8075 : Segment* Measure::undoGetSegmentR(SegmentType type, const Fraction& t)
     715              : {
     716         8075 :     Segment* s = findSegmentR(type, t);
     717         8075 :     if (s == 0) {
     718         3525 :         s = Factory::createSegment(this, type, t);
     719         3525 :         score()->undoAddElement(s);
     720              :     }
     721         8075 :     return s;
     722              : }
     723              : 
     724              : //---------------------------------------------------------
     725              : //   findFirstR
     726              : //    return first segment of type st at relative
     727              : //    position t.
     728              : //---------------------------------------------------------
     729              : 
     730       175704 : Segment* Measure::findFirstR(SegmentType st, const Fraction& t) const
     731              : {
     732              :     Segment* s;
     733              :     // search forwards
     734       307176 :     for (s = first(); s && s->rtick() <= t; s = s->next()) {
     735       297983 :         if (s->segmentType() & st) {
     736       166511 :             return s;
     737              :         }
     738              :     }
     739         9193 :     return 0;
     740              : }
     741              : 
     742          570 : Segment* Measure::getChordRestOrTimeTickSegment(const Fraction& f)
     743              : {
     744          570 :     Segment* seg = findSegment(SegmentType::ChordRest, f);
     745          570 :     if (!seg) {
     746          371 :         seg = findSegment(SegmentType::TimeTick, f);
     747              :     }
     748          570 :     if (!seg) {
     749          371 :         if (f - tick() == ticks()) { // end of measure
     750            3 :             seg = getSegment(SegmentType::TimeTick, f);
     751              :         } else {
     752          368 :             seg = getSegment(SegmentType::ChordRest, f);
     753              :         }
     754              :     }
     755              : 
     756          570 :     return seg;
     757              : }
     758              : 
     759           51 : Segment* Measure::undoGetChordRestOrTimeTickSegment(const Fraction& f)
     760              : {
     761           51 :     Segment* seg = findSegment(SegmentType::ChordRest, f);
     762           51 :     if (!seg) {
     763           19 :         seg = findSegment(SegmentType::TimeTick, f);
     764              :     }
     765           51 :     if (!seg) {
     766           19 :         if (f - tick() == ticks()) { // end of measure
     767            0 :             seg = undoGetSegment(SegmentType::TimeTick, f);
     768              :         } else {
     769           19 :             seg = undoGetSegment(SegmentType::ChordRest, f);
     770              :         }
     771              :     }
     772              : 
     773           51 :     return seg;
     774              : }
     775              : 
     776              : //---------------------------------------------------------
     777              : //   getSegmentR
     778              : ///   Get a segment of type st at relative tick position t.
     779              : ///   If the segment does not exist, it is created.
     780              : //---------------------------------------------------------
     781              : 
     782        77604 : Segment* Measure::getSegmentR(SegmentType st, const Fraction& t)
     783              : {
     784        77604 :     Segment* s = findSegmentR(st, t);
     785        77604 :     if (!s) {
     786        57489 :         s = Factory::createSegment(this, st, t);
     787        57489 :         add(s);
     788              :     }
     789        77604 :     return s;
     790              : }
     791              : 
     792              : //---------------------------------------------------------
     793              : //   add
     794              : ///   Add new EngravingItem \a el to Measure.
     795              : //---------------------------------------------------------
     796              : 
     797        84773 : void Measure::add(EngravingItem* e)
     798              : {
     799        84773 :     if (e->ownershipParent() != this) {
     800           62 :         e->setOwnershipParent(this);
     801              :     }
     802              : 
     803        84773 :     ElementType type = e->type();
     804              : 
     805        84773 :     switch (type) {
     806        81092 :     case ElementType::SEGMENT:
     807              :     {
     808        81092 :         Segment* seg   = toSegment(e);
     809        81092 :         Fraction t     = seg->rtick();
     810              :         Segment* s;
     811              : 
     812       217066 :         for (s = first(); s && s->rtick() < t; s = s->next()) {
     813              :         }
     814       104348 :         while (s && s->rtick() == t) {
     815        44489 :             if (!seg->isChordRestType() && (seg->segmentType() == s->segmentType())) {
     816            1 :                 if (seg->isType(SegmentType::BarLineTypes)) {
     817              :                     // Barline segments are regenerated every layout
     818              :                     // We need to remove the regenerated segment when undoing to ensure the original element is added back to the score
     819            0 :                     m_segments.remove(s);
     820            0 :                     s = s->next();
     821            0 :                     continue;
     822              :                 }
     823              :                 /// HACK: REMOVED to prevent crash in 4.4.3.
     824              :                 /// Adding multiple identical segments may cause problems, so we should resolve this properly
     825              :                 // return;
     826              :             }
     827        44489 :             if (seg->goesBefore(s)) {
     828        21233 :                 break;
     829              :             }
     830        23256 :             s = s->next();
     831              :         }
     832        81092 :         seg->setOwnershipParent(this);
     833        81092 :         m_segments.insert(seg, s);
     834              :         //
     835              :         // update measure flags
     836              :         //
     837        81092 :         if (seg->header()) {
     838         8864 :             seg->measure()->setHeader(true);
     839              :         }
     840        81092 :         if (seg->trailer()) {
     841            0 :             seg->measure()->setTrailer(true);
     842              :         }
     843              :     }
     844        81092 :     break;
     845              : 
     846         2336 :     case ElementType::MEASURE_NUMBER:
     847         2336 :         if (e->staffIdx() < m_mstaves.size()) {
     848         2336 :             m_mstaves[e->staffIdx()]->setMeasureNumber(toMeasureNumber(e));
     849              :         }
     850         2336 :         break;
     851              : 
     852            0 :     case ElementType::MMREST_RANGE:
     853            0 :         if (e->staffIdx() < m_mstaves.size()) {
     854            0 :             m_mstaves[e->staffIdx()]->setMMRangeText(toMMRestRange(e));
     855              :         }
     856            0 :         break;
     857              : 
     858            1 :     case ElementType::SPACER:
     859              :     {
     860            1 :         Spacer* sp = toSpacer(e);
     861            1 :         switch (sp->spacerType()) {
     862            0 :         case SpacerType::UP:
     863            0 :             m_mstaves[e->staffIdx()]->setVspacerUp(sp);
     864            0 :             break;
     865            1 :         case SpacerType::DOWN:
     866              :         case SpacerType::FIXED:
     867            1 :             m_mstaves[e->staffIdx()]->setVspacerDown(sp);
     868            1 :             break;
     869              :         }
     870            1 :         sp->setGap(sp->gap());            // trigger relayout
     871              :     }
     872            1 :     break;
     873          391 :     case ElementType::JUMP:
     874              :     case ElementType::MARKER:
     875          391 :         if (e && (e->isJump() || (e->isMarker() && toMarker(e)->isRightMarker()))) {
     876              :             // "To coda" markings act like jumps
     877          240 :             setProperty(Pid::REPEAT_JUMP, true);
     878              :         }
     879          391 :         el().push_back(e);
     880          391 :         break;
     881              : 
     882            0 :     case ElementType::HBOX:
     883            0 :         if (e->staff()) {
     884            0 :             e->mutldata()->setMag(e->staff()->staffMag(tick()));                 // ?!
     885              :         }
     886            0 :         el().push_back(e);
     887            0 :         break;
     888              : 
     889            0 :     case ElementType::MEASURE:
     890            0 :         m_mmRest = toMeasure(e);
     891            0 :         break;
     892              : 
     893           18 :     case ElementType::STAFFTYPE_CHANGE:
     894              :     {
     895           18 :         StaffTypeChange* staffTypeChange = toStaffTypeChange(e);
     896           18 :         const StaffType* templateStaffType = staffTypeChange->staffType();
     897              : 
     898           18 :         Staff* staff = staffTypeChange->staff();
     899              : 
     900              :         // This will need to point to the stafftype element within the stafftypelist for the staff
     901           18 :         StaffType* newStaffType = nullptr;
     902              : 
     903           18 :         if (templateStaffType) {
     904              :             // executed on read, undo/redo, clone
     905              :             // setStaffType adds a copy to stafftypelist and returns a pointer to that element within stafftypelist
     906           18 :             newStaffType = staff->setStaffType(tick(), *templateStaffType);
     907              :         } else {
     908              :             // executed on add from palette
     909              :             // staffType returns a pointer to the current stafftype element in the list
     910              :             // setStaffType will make a copy and return a pointer to that element within list
     911            0 :             templateStaffType = staff->staffType(tick());
     912            0 :             newStaffType = staff->setStaffType(tick(), *templateStaffType);
     913              :         }
     914              : 
     915           18 :         staff->staffTypeListChanged(tick());
     916           18 :         staffTypeChange->setStaffType(newStaffType, false);
     917              : 
     918           18 :         MeasureBase::add(e);
     919              :     }
     920           18 :         return;
     921              : 
     922          935 :     default:
     923          935 :         MeasureBase::add(e);
     924          935 :         return;
     925              :     }
     926              : 
     927        83820 :     e->added();
     928              : }
     929              : 
     930              : //---------------------------------------------------------
     931              : //   remove
     932              : ///   Remove EngravingItem \a el from Measure.
     933              : //---------------------------------------------------------
     934              : 
     935         2531 : void Measure::remove(EngravingItem* e)
     936              : {
     937         2531 :     assert(e->ownershipParent() == this);
     938         2531 :     assert(e->score() == score());
     939              : 
     940         2531 :     switch (e->type()) {
     941         2498 :     case ElementType::SEGMENT:
     942              :     {
     943         2498 :         Segment* s = toSegment(e);
     944         2498 :         m_segments.remove(s);
     945              :         //
     946              :         // update measure flags
     947              :         //
     948         2498 :         if (s->header()) {
     949           16 :             s->measure()->checkHeader();
     950              :         }
     951         2498 :         if (s->trailer()) {
     952            4 :             s->measure()->checkTrailer();
     953              :         }
     954              :     }
     955         2498 :     break;
     956              : 
     957            0 :     case ElementType::MEASURE_NUMBER:
     958            0 :         m_mstaves[e->staffIdx()]->setMeasureNumber(nullptr);
     959            0 :         break;
     960              : 
     961            0 :     case ElementType::MMREST_RANGE:
     962            0 :         m_mstaves[e->staffIdx()]->setMMRangeText(nullptr);
     963            0 :         break;
     964              : 
     965            0 :     case ElementType::SPACER:
     966            0 :         switch (toSpacer(e)->spacerType()) {
     967            0 :         case SpacerType::DOWN:
     968              :         case SpacerType::FIXED:
     969            0 :             m_mstaves[e->staffIdx()]->setVspacerDown(0);
     970            0 :             break;
     971            0 :         case SpacerType::UP:
     972            0 :             m_mstaves[e->staffIdx()]->setVspacerUp(0);
     973            0 :             break;
     974              :         }
     975            0 :         break;
     976              : 
     977            4 :     case ElementType::JUMP:
     978              :     case ElementType::MARKER:
     979            4 :         if (e->isJump() || (e->isMarker() && toMarker(e)->isRightMarker())) {
     980            4 :             setProperty(Pid::REPEAT_JUMP, false);
     981              :         }
     982              :         [[fallthrough]];
     983              :     case ElementType::HBOX:
     984            4 :         if (!el().remove(e)) {
     985            0 :             LOGD("Measure(%p)::remove(%s,%p) not found", this, e->typeName(), e);
     986              :         }
     987            4 :         break;
     988              : 
     989            0 :     case ElementType::CLEF:
     990              :     case ElementType::CHORD:
     991              :     case ElementType::REST:
     992              :     case ElementType::MMREST:
     993              :     case ElementType::TIMESIG:
     994            0 :         for (Segment* segment = first(); segment; segment = segment->next()) {
     995            0 :             size_t staves = score()->nstaves();
     996            0 :             size_t tracks = staves * VOICES;
     997            0 :             for (track_idx_t track = 0; track < tracks; ++track) {
     998            0 :                 EngravingItem* ee = segment->element(track);
     999            0 :                 if (ee == e) {
    1000            0 :                     segment->setElement(track, nullptr);
    1001            0 :                     e->removed();
    1002            0 :                     return;
    1003              :                 }
    1004              :             }
    1005              :         }
    1006            0 :         LOGD("Measure::remove: %s %p not found", e->typeName(), e);
    1007            0 :         break;
    1008              : 
    1009            0 :     case ElementType::MEASURE:
    1010            0 :         m_mmRest = 0;
    1011            0 :         break;
    1012              : 
    1013            0 :     case ElementType::STAFFTYPE_CHANGE:
    1014              :     {
    1015            0 :         StaffTypeChange* stc = toStaffTypeChange(e);
    1016            0 :         Staff* staff = stc->staff();
    1017            0 :         if (staff) {
    1018              :             // st currently points to an list element that is about to be removed
    1019              :             // make a copy now to use on undo/redo
    1020            0 :             StaffType* st = new StaffType(*stc->staffType());
    1021            0 :             if (!tick().isZero()) {
    1022            0 :                 staff->removeStaffType(tick());
    1023              :             }
    1024            0 :             stc->setStaffType(st, true);
    1025              :         }
    1026            0 :         MeasureBase::remove(e);
    1027              :     }
    1028            0 :         return;
    1029              : 
    1030           29 :     default:
    1031           29 :         MeasureBase::remove(e);
    1032           29 :         return;
    1033              :     }
    1034              : 
    1035         2502 :     e->removed();
    1036              : }
    1037              : 
    1038              : //---------------------------------------------------------
    1039              : //   change
    1040              : //---------------------------------------------------------
    1041              : 
    1042            0 : void Measure::change(EngravingItem* o, EngravingItem* n)
    1043              : {
    1044            0 :     if (o->isTuplet()) {
    1045            0 :         Tuplet* t = toTuplet(n);
    1046            0 :         for (DurationElement* e : t->elements()) {
    1047            0 :             e->setTuplet(t);
    1048              :         }
    1049              :     } else {
    1050            0 :         remove(o);
    1051            0 :         add(n);
    1052              :     }
    1053            0 : }
    1054              : 
    1055              : //---------------------------------------------------------
    1056              : //   spatiumChanged
    1057              : //---------------------------------------------------------
    1058              : 
    1059            0 : void Measure::spatiumChanged(double /*oldValue*/, double /*newValue*/)
    1060              : {
    1061            0 : }
    1062              : 
    1063              : //-------------------------------------------------------------------
    1064              : //   moveTicks
    1065              : //    Also adjust endBarLine if measure len has changed. For this
    1066              : //    diff == 0 cannot be optimized away
    1067              : //-------------------------------------------------------------------
    1068              : 
    1069        48395 : void Measure::moveTicks(const Fraction& diff)
    1070              : {
    1071              :     // This part must be run also for diff = 0
    1072       192239 :     for (Segment* segment = last(); segment; segment = segment->prev()) {
    1073       143844 :         if (segment->segmentType() & (SegmentType::EndBarLine | SegmentType::TimeSigAnnounce)) {
    1074        21260 :             segment->setRtick(ticks());
    1075              :         }
    1076              :     }
    1077        48395 :     if (diff.numerator() == 0) {
    1078        46662 :         return;
    1079              :     }
    1080         1733 :     std::set<Tuplet*> tuplets;
    1081         1733 :     setTick(tick() + diff);
    1082         5789 :     for (Segment* segment = last(); segment; segment = segment->prev()) {
    1083         4056 :         if (segment->isChordRestType()) {
    1084              :             // Tuplet ticks are stored as absolute ticks, so they must be adjusted,
    1085              :             // outer tuplets of nested ones too. But each tuplet must only be adjusted once.
    1086        12114 :             for (EngravingItem* e : segment->elist()) {
    1087        10004 :                 if (e) {
    1088         2491 :                     ChordRest* cr = toChordRest(e);
    1089         2499 :                     for (Tuplet* tuplet = cr->tuplet(); tuplet && tuplets.insert(tuplet).second; tuplet = tuplet->tuplet()) {
    1090            8 :                         tuplet->setTick(tuplet->tick() + diff);
    1091              :                     }
    1092              :                 }
    1093              :             }
    1094              :         }
    1095              :     }
    1096         1733 :     tuplets.clear();
    1097         1733 : }
    1098              : 
    1099              : //---------------------------------------------------------
    1100              : //   removeStaves
    1101              : //---------------------------------------------------------
    1102              : 
    1103          325 : void Measure::removeStaves(staff_idx_t sStaff, staff_idx_t eStaff)
    1104              : {
    1105         1341 :     for (Segment* s = first(); s; s = s->next()) {
    1106         2032 :         for (int staff = static_cast<int>(eStaff) - 1; staff >= static_cast<int>(sStaff); --staff) {
    1107         1016 :             s->removeStaff(staff);
    1108              :         }
    1109              :     }
    1110          325 :     for (EngravingItem* e : el()) {
    1111            0 :         if (e->track() == muse::nidx) {
    1112            0 :             continue;
    1113              :         }
    1114            0 :         voice_idx_t voice = e->voice();
    1115            0 :         staff_idx_t staffIdx = e->staffIdx();
    1116            0 :         if (staffIdx >= eStaff) {
    1117            0 :             staffIdx -= eStaff - sStaff;
    1118            0 :             e->setTrack(staffIdx * VOICES + voice);
    1119              :         }
    1120              :     }
    1121          325 : }
    1122              : 
    1123              : //---------------------------------------------------------
    1124              : //   insertStaves
    1125              : //---------------------------------------------------------
    1126              : 
    1127          506 : void Measure::insertStaves(staff_idx_t sStaff, staff_idx_t eStaff)
    1128              : {
    1129          506 :     for (EngravingItem* e : el()) {
    1130            0 :         if (e->track() == muse::nidx) {
    1131            0 :             continue;
    1132              :         }
    1133            0 :         staff_idx_t staffIdx = e->staffIdx();
    1134            0 :         if (moveDownWhenAddingStaves(e, sStaff, eStaff)) {
    1135            0 :             voice_idx_t voice = e->voice();
    1136            0 :             staffIdx += eStaff - sStaff;
    1137            0 :             e->setTrack(staffIdx * VOICES + voice);
    1138              :         }
    1139              :     }
    1140         2139 :     for (Segment* s = first(); s; s = s->next()) {
    1141         3266 :         for (staff_idx_t staff = sStaff; staff < eStaff; ++staff) {
    1142         1633 :             s->insertStaff(staff);
    1143              :         }
    1144              :     }
    1145          506 : }
    1146              : 
    1147              : //---------------------------------------------------------
    1148              : //   cmdRemoveStaves
    1149              : //---------------------------------------------------------
    1150              : 
    1151          253 : void Measure::cmdRemoveStaves(staff_idx_t sStaff, staff_idx_t eStaff)
    1152              : {
    1153          253 :     track_idx_t sTrack = sStaff * VOICES;
    1154          253 :     track_idx_t eTrack = eStaff * VOICES;
    1155              : 
    1156         1046 :     for (Segment* s = first(); s; s = s->next()) {
    1157         3965 :         for (int track = static_cast<int>(eTrack) - 1; track >= static_cast<int>(sTrack); --track) {
    1158         3172 :             EngravingItem* el = s->element(track);
    1159         3172 :             if (el) {
    1160          844 :                 el->undoUnlink();
    1161          844 :                 score()->doUndoRemoveElement(el);
    1162              :             }
    1163              :         }
    1164              : 
    1165              :         // Create copy, because s->annotations() will be modified during the loop
    1166          793 :         std::vector<EngravingItem*> annotations = s->annotations();
    1167          804 :         for (EngravingItem* e : annotations) {
    1168           11 :             if (allowRemoveWhenRemovingStaves(e, sStaff, eStaff)) {
    1169            6 :                 e->undoUnlink();
    1170            6 :                 score()->doUndoRemoveElement(e);
    1171              :             }
    1172              :         }
    1173          793 :     }
    1174              : 
    1175          253 :     for (EngravingItem* e : el()) {
    1176            0 :         if (e->track() == muse::nidx) {
    1177            0 :             continue;
    1178              :         }
    1179              : 
    1180            0 :         if (allowRemoveWhenRemovingStaves(e, sStaff, eStaff)) {
    1181            0 :             e->undoUnlink();
    1182            0 :             score()->doUndoRemoveElement(e);
    1183              :         }
    1184              :     }
    1185              : 
    1186          253 :     score()->undo(new RemoveStaves(this, sStaff, eStaff));
    1187              : 
    1188          506 :     for (int i = static_cast<int>(eStaff) - 1; i >= static_cast<int>(sStaff); --i) {
    1189          253 :         MStaff* ms = *(m_mstaves.begin() + i);
    1190          253 :         score()->undo(new RemoveMStaff(this, ms, i));
    1191              :     }
    1192          253 :     score()->undoUpdatePlayCountText(this);
    1193          253 : }
    1194              : 
    1195              : //---------------------------------------------------------
    1196              : //   cmdAddStaves
    1197              : //---------------------------------------------------------
    1198              : 
    1199          376 : void Measure::cmdAddStaves(staff_idx_t sStaff, staff_idx_t eStaff, bool createRest)
    1200              : {
    1201          376 :     score()->undo(new InsertStaves(this, sStaff, eStaff));
    1202              : 
    1203          376 :     Segment* ts = findSegment(SegmentType::TimeSig, tick());
    1204          376 :     Segment* bs = findSegmentR(SegmentType::EndBarLine, ticks());
    1205              : 
    1206          752 :     for (staff_idx_t i = sStaff; i < eStaff; ++i) {
    1207          376 :         Staff* staff = score()->staff(i);
    1208          376 :         MStaff* ms   = new MStaff;
    1209          376 :         ms->setLines(Factory::createStaffLines(this));
    1210          376 :         ms->lines()->setTrack(i * VOICES);
    1211          376 :         ms->lines()->setVisible(!staff->isLinesInvisible(tick()));
    1212          376 :         score()->undo(new InsertMStaff(this, ms, i));
    1213              :     }
    1214              : 
    1215          376 :     if (!createRest && !ts) {
    1216           22 :         return;
    1217              :     }
    1218              : 
    1219              :     // collect unique staves (only one instance for linked staves):
    1220              : 
    1221          354 :     std::vector<staff_idx_t> sl;
    1222          708 :     for (staff_idx_t staffIdx = sStaff; staffIdx < eStaff; ++staffIdx) {
    1223          354 :         Staff* s = score()->staff(staffIdx);
    1224          354 :         if (s->links()) {
    1225            0 :             bool alreadyInList = false;
    1226            0 :             for (staff_idx_t idx : sl) {
    1227            0 :                 if (s->links()->contains(score()->staff(idx))) {
    1228            0 :                     alreadyInList = true;
    1229            0 :                     break;
    1230              :                 }
    1231              :             }
    1232            0 :             if (alreadyInList) {
    1233            0 :                 continue;
    1234              :             }
    1235              :         }
    1236          354 :         sl.push_back(staffIdx);
    1237              :     }
    1238              : 
    1239          708 :     for (staff_idx_t staffIdx : sl) {
    1240          354 :         if (createRest) {
    1241          341 :             score()->setRest(tick(), staffIdx * VOICES, ticks(), false, 0, m_timesig == ticks());
    1242              :         }
    1243              : 
    1244              :         // replicate time signature
    1245          354 :         if (ts) {
    1246           61 :             TimeSig* ots = 0;
    1247           61 :             bool constructed = false;
    1248          209 :             for (track_idx_t track = 0; track < m_mstaves.size() * VOICES; ++track) {
    1249          189 :                 if (ts->element(track)) {
    1250           41 :                     ots = toTimeSig(ts->element(track));
    1251           41 :                     break;
    1252              :                 }
    1253              :             }
    1254           61 :             if (!ots) {
    1255              :                 // no time signature found; use measure timesig to construct one
    1256           20 :                 ots = Factory::createTimeSig(score()->dummy());
    1257           20 :                 ots->setSig(timesig());
    1258           20 :                 constructed = true;
    1259              :             }
    1260              :             // do no replicate local time signatures
    1261           61 :             if (ots && !ots->isLocal()) {
    1262           59 :                 TimeSig* timesig = Factory::copyTimeSig(*ots);
    1263           59 :                 timesig->setTrack(staffIdx * VOICES);
    1264           59 :                 timesig->setOwnershipParent(ts);
    1265           59 :                 timesig->setSig(ots->sig(), ots->timeSigType());
    1266           59 :                 score()->undoAddElement(timesig);
    1267           59 :                 if (constructed) {
    1268           20 :                     delete ots;
    1269              :                 }
    1270              :             }
    1271              :         }
    1272              : 
    1273              :         // replicate barline
    1274          354 :         if (bs) {
    1275          326 :             BarLine* obl = nullptr;
    1276         4502 :             for (track_idx_t track = 0; track < m_mstaves.size() * VOICES; ++track) {
    1277         4182 :                 EngravingItem* e = bs->element(track);
    1278         4182 :                 if (e && !e->generated()) {
    1279            6 :                     obl = toBarLine(e);
    1280            6 :                     break;
    1281              :                 }
    1282              :             }
    1283          326 :             if (obl) {
    1284            6 :                 BarLine* barline = Factory::copyBarLine(*obl);
    1285            6 :                 barline->setSpanStaff(score()->staff(staffIdx)->barLineSpan());
    1286            6 :                 barline->setTrack(staffIdx * VOICES);
    1287            6 :                 barline->setOwnershipParent(bs);
    1288            6 :                 barline->setGenerated(false);
    1289            6 :                 score()->undoAddElement(barline);
    1290              :             }
    1291              :         }
    1292              :     }
    1293          354 : }
    1294              : 
    1295              : //---------------------------------------------------------
    1296              : //   insertMStaff
    1297              : //---------------------------------------------------------
    1298              : 
    1299          670 : void Measure::insertMStaff(MStaff* staff, staff_idx_t idx)
    1300              : {
    1301          670 :     m_mstaves.insert(m_mstaves.begin() + idx, staff);
    1302         2660 :     for (staff_idx_t staffIdx = 0; staffIdx < m_mstaves.size(); ++staffIdx) {
    1303         1990 :         m_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
    1304              :     }
    1305          670 : }
    1306              : 
    1307              : //---------------------------------------------------------
    1308              : //   removeMStaff
    1309              : //---------------------------------------------------------
    1310              : 
    1311          325 : void Measure::removeMStaff(MStaff* /*staff*/, staff_idx_t idx)
    1312              : {
    1313          325 :     m_mstaves.erase(m_mstaves.begin() + idx);
    1314          873 :     for (staff_idx_t staffIdx = 0; staffIdx < m_mstaves.size(); ++staffIdx) {
    1315          548 :         m_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
    1316              :     }
    1317          325 : }
    1318              : 
    1319              : //---------------------------------------------------------
    1320              : //   insertStaff
    1321              : //---------------------------------------------------------
    1322              : 
    1323          164 : void Measure::insertStaff(Staff* staff, staff_idx_t staffIdx)
    1324              : {
    1325          836 :     for (Segment* s = first(); s; s = s->next()) {
    1326          672 :         s->insertStaff(staffIdx);
    1327              :     }
    1328              : 
    1329          164 :     MStaff* ms = new MStaff;
    1330          164 :     ms->setLines(Factory::createStaffLines(this));
    1331          164 :     ms->lines()->setTrack(staffIdx * VOICES);
    1332          164 :     ms->lines()->setVisible(!staff->isLinesInvisible(tick()));
    1333          164 :     insertMStaff(ms, staffIdx);
    1334          164 : }
    1335              : 
    1336              : //---------------------------------------------------------
    1337              : //   staffPageBoundingRect
    1338              : //---------------------------------------------------------
    1339              : 
    1340         4000 : RectF Measure::staffPageBoundingRect(staff_idx_t staffIdx) const
    1341              : {
    1342         4000 :     System* s = system();
    1343         4000 :     IF_ASSERT_FAILED(s) {
    1344            0 :         return RectF();
    1345              :     }
    1346         4000 :     RectF sysStaffPageBbox = s->staff(staffIdx)->bbox().translated(s->pagePos());
    1347         4000 :     RectF measurePageBbox = pageBoundingRect();
    1348         4000 :     return RectF(measurePageBbox.x(), sysStaffPageBbox.y(), measurePageBbox.width(), sysStaffPageBbox.height());
    1349              : }
    1350              : 
    1351              : //---------------------------------------------------------
    1352              : //   acceptDrop
    1353              : //---------------------------------------------------------
    1354              : 
    1355              : /**
    1356              :  Return true if an EngravingItem of type \a type can be dropped on a Measure
    1357              : */
    1358              : 
    1359            0 : bool Measure::acceptDrop(EditData& data) const
    1360              : {
    1361            0 :     const EngravingItem* e = data.dropElement;
    1362              : 
    1363            0 :     if (data.track == muse::nidx || !system()) {
    1364            0 :         return false;
    1365              :     }
    1366              : 
    1367            0 :     const staff_idx_t staffIdx = track2staff(data.track);
    1368              : 
    1369              :     //! NOTE: Should match NotationInteraction::dragMeasureAnchorElement
    1370            0 :     switch (e->type()) {
    1371            0 :     case ElementType::VBOX:
    1372              :     case ElementType::TBOX:
    1373              :     case ElementType::FBOX:
    1374              :     case ElementType::HBOX: {
    1375            0 :         const Measure* m = isMMRest() ? mmRestFirst() : this;
    1376            0 :         for (staff_idx_t staffIdxLoop = 0; staffIdxLoop < score()->nstaves(); ++staffIdxLoop) {
    1377            0 :             if (m->isMeasureRepeatGroupWithPrevM(staffIdxLoop)) {
    1378            0 :                 return false;
    1379              :             }
    1380              :         }
    1381              :         [[fallthrough]];
    1382              :     }
    1383              : 
    1384              :     case ElementType::MEASURE_NUMBER:
    1385              :     case ElementType::JUMP:
    1386              :     case ElementType::MARKER:
    1387              :     case ElementType::VOLTA:
    1388              :     case ElementType::GRADUAL_TEMPO_CHANGE:
    1389              :     case ElementType::KEYSIG:
    1390              :     case ElementType::TIMESIG:
    1391              :         // Drop to all staves or single staff depending on modifier
    1392            0 :         return true;
    1393              : 
    1394            0 :     case ElementType::BRACKET:
    1395              :     case ElementType::MEASURE_REPEAT:
    1396              :     case ElementType::MEASURE:
    1397              :     case ElementType::SPACER:
    1398              :     case ElementType::IMAGE:
    1399              :     case ElementType::BAR_LINE:
    1400              :     case ElementType::SYMBOL:
    1401              :     case ElementType::CLEF:
    1402              :     case ElementType::STAFFTYPE_CHANGE:
    1403              :         // Always drop to single staff
    1404            0 :         return true;
    1405              : 
    1406            0 :     case ElementType::STRING_TUNINGS:
    1407            0 :         return canAddStringTunings(staffIdx);
    1408              : 
    1409            0 :     case ElementType::ACTION_ICON:
    1410            0 :         switch (toActionIcon(e)->actionType()) {
    1411            0 :         case ActionIconType::VFRAME:
    1412              :         case ActionIconType::HFRAME:
    1413              :         case ActionIconType::TFRAME:
    1414              :         case ActionIconType::FFRAME:
    1415              :         case ActionIconType::MEASURE: {
    1416            0 :             const Measure* m = isMMRest() ? mmRestFirst() : this;
    1417            0 :             for (staff_idx_t staffIdxLoop = 0; staffIdxLoop < score()->nstaves(); ++staffIdxLoop) {
    1418            0 :                 if (m->isMeasureRepeatGroupWithPrevM(staffIdxLoop)) {
    1419            0 :                     return false;
    1420              :                 }
    1421              :             }
    1422            0 :             return true;
    1423              :         }
    1424            0 :         case ActionIconType::STAFF_TYPE_CHANGE:
    1425            0 :             return canAddStaffTypeChange(staffIdx);
    1426            0 :         default:
    1427            0 :             break;
    1428              :         }
    1429            0 :         break;
    1430              : 
    1431            0 :     default:
    1432            0 :         break;
    1433              :     }
    1434            0 :     return MeasureBase::acceptDrop(data);
    1435              : }
    1436              : 
    1437              : //---------------------------------------------------------
    1438              : //   drop
    1439              : ///   Drop element.
    1440              : ///   Handle a dropped element at position \a pos of given
    1441              : ///   element \a type and \a subtype.
    1442              : //---------------------------------------------------------
    1443              : 
    1444           17 : EngravingItem* Measure::drop(Transaction& tx, EditData& data)
    1445              : {
    1446           17 :     EngravingItem* e = data.dropElement;
    1447           17 :     staff_idx_t staffIdx = track2staff(data.track);
    1448           17 :     if (staffIdx == muse::nidx) {
    1449            0 :         delete e;
    1450            0 :         return nullptr;
    1451              :     }
    1452           17 :     Staff* staff = score()->staff(staffIdx);
    1453              : 
    1454           17 :     switch (e->type()) {
    1455            0 :     case ElementType::MARKER:
    1456              :     case ElementType::JUMP:
    1457            0 :         e->setOwnershipParent(this);
    1458            0 :         e->setTrack(0);
    1459            0 :         score()->undoAddElement(e);
    1460            0 :         return e;
    1461              : 
    1462            0 :     case ElementType::STRING_TUNINGS:
    1463              :     {
    1464            0 :         staff = staff->isPrimaryStaff() ? staff : staff->primaryStaff();
    1465            0 :         if (!staff) {
    1466            0 :             delete e;
    1467            0 :             return nullptr;
    1468              :         }
    1469            0 :         staffIdx = staff->idx();
    1470            0 :         Segment* parentSeg = first(SegmentType::Duration);
    1471            0 :         if (!parentSeg) {
    1472            0 :             delete e;
    1473            0 :             return nullptr;
    1474              :         }
    1475            0 :         e->setOwnershipParent(parentSeg);
    1476            0 :         e->setTrack(staff2track(staffIdx));
    1477            0 :         score()->undoAddElement(e);
    1478            0 :         return e;
    1479              :     }
    1480              : 
    1481            0 :     case ElementType::MEASURE_NUMBER:
    1482            0 :         undoChangeProperty(Pid::MEASURE_NUMBER_MODE, static_cast<int>(MeasureNumberMode::SHOW));
    1483            0 :         delete e;
    1484            0 :         break;
    1485              : 
    1486            0 :     case ElementType::BRACKET:
    1487              :     {
    1488            0 :         Selection sel = score()->selection();
    1489            0 :         staff_idx_t firstStaff = sel.staffStart();
    1490            0 :         staff_idx_t lastStaff = sel.staffEnd() - 1;
    1491            0 :         size_t level = 0;
    1492            0 :         for (staff_idx_t idx = 0; idx < score()->nstaves(); ++idx) {
    1493            0 :             for (const BracketItem* bi : score()->brackets(idx)) {
    1494            0 :                 if (bi->intersects(firstStaff, lastStaff)) {
    1495            0 :                     level = std::max(level, bi->column() + 1);
    1496              :                 }
    1497              :             }
    1498              :         }
    1499              : 
    1500            0 :         Bracket* b = toBracket(e);
    1501            0 :         if (sel.isRange()) {
    1502            0 :             EditStaffBrackets::undoAddBracket(score(), staff, level, b->bracketType(), sel.staffEnd() - sel.staffStart());
    1503              :         } else {
    1504            0 :             EditStaffBrackets::undoAddBracket(score(), staff, level, b->bracketType(), 1);
    1505              :         }
    1506            0 :         delete b;
    1507            0 :     }
    1508            0 :     break;
    1509              : 
    1510           12 :     case ElementType::CLEF:
    1511           12 :         EditClef::undoChangeClef(tx, score(), staff, this, toClef(e)->clefType());
    1512           12 :         delete e;
    1513           12 :         break;
    1514              : 
    1515            0 :     case ElementType::KEYSIG:
    1516              :     {
    1517            0 :         KeySigEvent k = toKeySig(e)->keySigEvent();
    1518            0 :         delete e;
    1519              : 
    1520            0 :         if (data.modifiers & ControlModifier) {
    1521              :             // apply only to this stave
    1522            0 :             EditKeySig::undoChangeKeySig(tx, score(), staff, tick(), k);
    1523              :         } else {
    1524              :             // apply to all staves:
    1525            0 :             for (Staff* s : score()->staves()) {
    1526            0 :                 EditKeySig::undoChangeKeySig(tx, score(), s, tick(), k);
    1527              :             }
    1528              :         }
    1529              : 
    1530            0 :         break;
    1531            0 :     }
    1532              : 
    1533            4 :     case ElementType::TIMESIG: {
    1534            4 :         EditTimeSig::addTimeSig(tx, score(), this, staffIdx, toTimeSig(e), data.modifiers & ControlModifier);
    1535            4 :         break;
    1536              :     }
    1537              : 
    1538            0 :     case ElementType::SPACER:
    1539              :     {
    1540            0 :         Spacer* spacer = toSpacer(e);
    1541            0 :         spacer->setTrack(trackZeroVoice(data.track));
    1542            0 :         spacer->setOwnershipParent(this);
    1543            0 :         if (spacer->spacerType() == SpacerType::FIXED) {
    1544            0 :             double gap = spatium() * 10;
    1545            0 :             System* s = system();
    1546            0 :             const staff_idx_t nextVisStaffIdx = s->nextVisibleStaff(staffIdx);
    1547            0 :             const bool systemEnd = (nextVisStaffIdx == muse::nidx);
    1548            0 :             if (systemEnd) {
    1549            0 :                 System* ns = 0;
    1550            0 :                 for (System* ts : score()->systems()) {
    1551            0 :                     if (ns) {
    1552            0 :                         ns = ts;
    1553            0 :                         break;
    1554              :                     }
    1555            0 :                     if (ts == s) {
    1556            0 :                         ns = ts;
    1557              :                     }
    1558              :                 }
    1559            0 :                 if (ns == s) {
    1560            0 :                     double y1 = s->staffYpage(staffIdx);
    1561            0 :                     double y2 = s->page()->height() - s->page()->bm();
    1562            0 :                     gap = y2 - y1 - score()->staff(staffIdx)->staffHeight();
    1563            0 :                 } else if (ns && ns->page() == s->page()) {
    1564            0 :                     double y1 = s->staffYpage(staffIdx);
    1565            0 :                     double y2 = ns->staffYpage(0);
    1566            0 :                     gap = y2 - y1 - score()->staff(staffIdx)->staffHeight();
    1567              :                 }
    1568              :             } else {
    1569            0 :                 double y1 = s->staffYpage(staffIdx);
    1570            0 :                 double y2 = s->staffYpage(nextVisStaffIdx);
    1571            0 :                 gap = y2 - y1 - score()->staff(staffIdx)->staffHeight();
    1572              :             }
    1573            0 :             spacer->setGap(Spatium::fromAbsolute(gap, spatium()));
    1574              :         }
    1575            0 :         score()->undoAddElement(spacer);
    1576            0 :         triggerLayout();
    1577            0 :         return spacer;
    1578              :     }
    1579              : 
    1580            1 :     case ElementType::BAR_LINE:
    1581              :     {
    1582            1 :         BarLine* bl = toBarLine(e);
    1583              : 
    1584            1 :         if (bl->playCount() != -1) {
    1585            0 :             undoChangeProperty(Pid::REPEAT_COUNT, bl->playCount());
    1586              :         }
    1587              : 
    1588              :         // if dropped bar line refers to span rather than to subtype
    1589              :         // or if Ctrl key used
    1590            1 :         if ((bl->spanFrom() && bl->spanTo()) || data.control()) {
    1591              :             // get existing bar line for this staff, and drop the change to it
    1592            0 :             Segment* seg = undoGetSegmentR(SegmentType::EndBarLine, ticks());
    1593            0 :             BarLine* cbl = toBarLine(seg->element(trackZeroVoice(data.track)));
    1594            0 :             if (cbl) {
    1595            0 :                 return cbl->drop(tx, data);
    1596              :             }
    1597            1 :         } else if (bl->barLineType() == BarLineType::START_REPEAT) {
    1598            0 :             Measure* m2 = isMMRest() ? mmRestFirst() : this;
    1599            0 :             for (size_t stIdx = 0; stIdx < score()->nstaves(); ++stIdx) {
    1600            0 :                 if (m2->isMeasureRepeatGroupWithPrevM(stIdx)) {
    1601            0 :                     MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT);
    1602            0 :                     return nullptr;
    1603              :                 }
    1604              :             }
    1605            0 :             for (Score* lscore : score()->scoreList()) {
    1606            0 :                 Measure* lmeasure = lscore->tick2measure(m2->tick());
    1607            0 :                 if (lmeasure) {
    1608            0 :                     lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
    1609              :                 }
    1610            0 :             }
    1611            1 :         } else if (bl->barLineType() == BarLineType::END_REPEAT) {
    1612            0 :             Measure* m2 = isMMRest() ? mmRestLast() : this;
    1613            0 :             for (size_t stIdx = 0; stIdx < score()->nstaves(); ++stIdx) {
    1614            0 :                 if (m2->isMeasureRepeatGroupWithNextM(stIdx)) {
    1615            0 :                     MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT);
    1616            0 :                     return nullptr;
    1617              :                 }
    1618              :             }
    1619            0 :             for (Score* lscore : score()->scoreList()) {
    1620            0 :                 Measure* lmeasure = lscore->tick2measure(m2->tick());
    1621            0 :                 if (lmeasure) {
    1622            0 :                     lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
    1623              :                 }
    1624            0 :             }
    1625            0 :             score()->undoUpdatePlayCountText(this);
    1626            1 :         } else if (bl->barLineType() == BarLineType::END_START_REPEAT) {
    1627            0 :             Measure* m2 = isMMRest() ? mmRestLast() : this;
    1628            0 :             for (size_t stIdx = 0; stIdx < score()->nstaves(); ++stIdx) {
    1629            0 :                 if (m2->isMeasureRepeatGroupWithNextM(stIdx)) {
    1630            0 :                     MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT);
    1631            0 :                     return nullptr;
    1632              :                 }
    1633              :             }
    1634            0 :             for (Score* lscore : score()->scoreList()) {
    1635            0 :                 Measure* lmeasure = lscore->tick2measure(m2->tick());
    1636            0 :                 if (lmeasure) {
    1637            0 :                     lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
    1638            0 :                     lmeasure = lmeasure->nextMeasure();
    1639            0 :                     if (lmeasure) {
    1640            0 :                         lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
    1641              :                     }
    1642              :                 }
    1643            0 :             }
    1644              :         } else {
    1645            1 :             Segment* seg = undoGetSegmentR(SegmentType::EndBarLine, ticks());
    1646              :             // if any staff lacks a barline, create one
    1647            2 :             for (size_t stIdx = 0; stIdx < score()->nstaves(); ++stIdx) {
    1648            1 :                 BarLine* staffBarLine = toBarLine(seg->element(stIdx * VOICES));
    1649            1 :                 if (!staffBarLine) {
    1650            0 :                     staffBarLine = Factory::createBarLine(seg);
    1651            0 :                     staffBarLine->setTrack(stIdx * VOICES);
    1652            0 :                     undoAddElement(staffBarLine);
    1653              :                 }
    1654              :             }
    1655              :             // drop to barline
    1656            1 :             return seg->element(trackZeroVoice(data.track))->drop(tx, data);
    1657              :         }
    1658            0 :         break;
    1659              :     }
    1660              : 
    1661            0 :     case ElementType::MEASURE_REPEAT:
    1662              :     {
    1663            0 :         int numMeasures = toMeasureRepeat(e)->numMeasures();
    1664            0 :         delete e;
    1665            0 :         EditMeasureRepeat::addMeasureRepeat(tx, score(), this, numMeasures, staffIdx);
    1666            0 :         break;
    1667              :     }
    1668            0 :     case ElementType::ACTION_ICON:
    1669            0 :         switch (toActionIcon(e)->actionType()) {
    1670            0 :         case ActionIconType::VFRAME:
    1671            0 :             return score()->insertBox(ElementType::VBOX, this);
    1672            0 :         case ActionIconType::HFRAME:
    1673            0 :             return score()->insertBox(ElementType::HBOX, this);
    1674            0 :         case ActionIconType::TFRAME:
    1675            0 :             return score()->insertBox(ElementType::TBOX, this);
    1676            0 :         case ActionIconType::FFRAME:
    1677              :         {
    1678            0 :             Score::InsertMeasureOptions options;
    1679            0 :             options.cloneBoxToAllParts = false;
    1680            0 :             return score()->insertBox(ElementType::FBOX, this, options);
    1681              :         }
    1682            0 :         case ActionIconType::MEASURE:
    1683            0 :             score()->insertMeasure(ElementType::MEASURE, this);
    1684            0 :             break;
    1685            0 :         case ActionIconType::STAFF_TYPE_CHANGE: {
    1686            0 :             if (!canAddStaffTypeChange(staffIdx)) {
    1687            0 :                 return nullptr;
    1688              :             }
    1689            0 :             EngravingItem* stc = Factory::createStaffTypeChange(this);
    1690            0 :             stc->setTrack(trackZeroVoice(data.track));
    1691            0 :             score()->undoAddElement(stc);
    1692            0 :             break;
    1693              :         }
    1694            0 :         default:
    1695            0 :             return MeasureBase::drop(tx, data);
    1696              :         }
    1697            0 :         break;
    1698              : 
    1699            0 :     case ElementType::STAFFTYPE_CHANGE:
    1700              :     {
    1701            0 :         e->setOwnershipParent(this);
    1702            0 :         e->setTrack(trackZeroVoice(data.track));
    1703            0 :         score()->undoAddElement(e);
    1704              :     }
    1705            0 :     break;
    1706              : 
    1707            0 :     case ElementType::VBOX:
    1708              :     case ElementType::TBOX:
    1709              :     case ElementType::FBOX:
    1710              :     case ElementType::HBOX:
    1711            0 :         return score()->insertBox(toMeasureBase(e), this);
    1712              : 
    1713            0 :     default:
    1714            0 :         return MeasureBase::drop(tx, data);
    1715              :     }
    1716              : 
    1717           16 :     return nullptr;
    1718              : }
    1719              : 
    1720              : //---------------------------------------------------------
    1721              : //   adjustToLen
    1722              : //    change actual measure len, adjust elements to
    1723              : //    new len
    1724              : //---------------------------------------------------------
    1725              : 
    1726           57 : void Measure::adjustToLen(Fraction nf, bool appendRestsIfNecessary)
    1727              : {
    1728           57 :     Fraction ol   = ticks();
    1729           57 :     Fraction nl   = nf;
    1730           57 :     Fraction diff = nl - ol;
    1731              : 
    1732           57 :     Fraction startTick = endTick();
    1733           57 :     if (diff < Fraction(0, 1)) {
    1734           36 :         startTick += diff;
    1735              :     }
    1736              : 
    1737           57 :     score()->undoInsertTime(startTick, diff);
    1738              : 
    1739          118 :     for (Score* s : score()->scoreList()) {
    1740           61 :         s->undo(new InsertTime(s, startTick, diff));
    1741           61 :         Measure* m = s->tick2measure(tick());
    1742           61 :         s->undo(new ChangeMeasureLen(m, nf));
    1743           61 :         if (nl > ol) {
    1744              :             // move EndBarLine, TimeSigAnnounce, KeySigAnnounce
    1745           18 :             for (Segment* seg = m->first(); seg; seg = seg->next()) {
    1746            6 :                 if (seg->segmentType() & (SegmentType::EndBarLine | SegmentType::CourtesyTimeSigTypes | SegmentType::CourtesyKeySigTypes)) {
    1747            0 :                     seg->setRtick(nl);
    1748              :                 }
    1749              :             }
    1750              :         }
    1751           57 :     }
    1752           57 :     Score* s      = score()->masterScore();
    1753           57 :     Measure* m    = s->tick2measure(tick());
    1754           57 :     std::vector<staff_idx_t> sl = s->uniqueStaves();
    1755              : 
    1756          118 :     for (staff_idx_t staffIdx : sl) {
    1757           61 :         int rests  = 0;
    1758           61 :         int chords = 0;
    1759           61 :         Rest* rest = 0;
    1760           83 :         for (Segment* segment = m->first(); segment; segment = segment->next()) {
    1761           22 :             track_idx_t strack = staffIdx * VOICES;
    1762           22 :             track_idx_t etrack = strack + VOICES;
    1763          110 :             for (track_idx_t track = strack; track < etrack; ++track) {
    1764           88 :                 EngravingItem* e = segment->element(track);
    1765           88 :                 if (e) {
    1766           22 :                     if (e->isRest()) {
    1767            0 :                         ++rests;
    1768            0 :                         rest = toRest(e);
    1769           22 :                     } else if (e->isChord()) {
    1770            6 :                         ++chords;
    1771              :                     }
    1772              :                 }
    1773              :             }
    1774              :         }
    1775           61 :         Fraction stretch = s->staff(staffIdx)->timeStretch(tick());
    1776              :         // if just a single rest
    1777           61 :         if (rests == 1 && chords == 0) {
    1778              :             // if measure value didn't change, stick to whole measure rest
    1779            0 :             if (m_timesig == nf) {
    1780            0 :                 rest->undoChangeProperty(Pid::DURATION, nf * stretch);
    1781            0 :                 rest->undoChangeProperty(Pid::DURATION_TYPE_WITH_DOTS, DurationTypeWithDots(DurationType::V_MEASURE));
    1782              :             } else {          // if measure value did change, represent with rests actual measure value
    1783              :                 // convert the measure duration in a list of values (no dots for rests)
    1784            0 :                 std::vector<TDuration> durList = toRhythmicDurationList(nf * stretch,
    1785              :                                                                         /*isRest=*/ true,
    1786            0 :                                                                         /*rtickStart=*/ Fraction(0, 1),
    1787            0 :                                                                         /*nominal=*/ score()->sigmap()->timesig(tick().ticks()).nominal(),
    1788              :                                                                         /*measure=*/ this,
    1789              :                                                                         /*maxDots=*/ 0,
    1790            0 :                                                                         stretch);
    1791            0 :                 if (durList.empty()) {
    1792            0 :                     LOGD("Could not make durations for: %d/%d", (nf * stretch).numerator(), (nf * stretch).denominator());
    1793            0 :                     continue;
    1794              :                 }
    1795              :                 // set the existing rest to the first value of the duration list
    1796            0 :                 TDuration firstDur = durList[0];
    1797            0 :                 rest->undoChangeProperty(Pid::DURATION, firstDur.isMeasure() ? ticks() : firstDur.fraction());
    1798            0 :                 rest->undoChangeProperty(Pid::DURATION_TYPE_WITH_DOTS, durList[0].typeWithDots());
    1799              : 
    1800              :                 // add rests for any other duration list value
    1801            0 :                 Fraction tickOffset = tick() + rest->actualTicks();
    1802            0 :                 for (unsigned i = 1; i < durList.size(); i++) {
    1803            0 :                     Rest* newRest = Factory::createRest(s->dummy());
    1804            0 :                     TDuration dur = durList.at(i);
    1805            0 :                     newRest->setDurationType(dur);
    1806            0 :                     newRest->setTicks(dur.isMeasure() ? ticks() : dur.fraction());
    1807            0 :                     newRest->setTrack(rest->track());
    1808            0 :                     score()->undoAddCR(newRest, this, tickOffset);
    1809            0 :                     tickOffset += newRest->actualTicks();
    1810              :                 }
    1811            0 :             }
    1812            0 :             continue;
    1813            0 :         }
    1814              : 
    1815           61 :         track_idx_t strack = staffIdx * VOICES;
    1816           61 :         track_idx_t etrack = strack + VOICES;
    1817              : 
    1818          305 :         for (track_idx_t trk = strack; trk < etrack; ++trk) {
    1819          244 :             Fraction n = diff;
    1820          244 :             bool rFlag = false;
    1821          244 :             if (n < Fraction(0, 1)) {
    1822          167 :                 for (Segment* segment = m->last(); segment;) {
    1823            8 :                     Segment* pseg = segment->prev();
    1824            8 :                     if (segment->segmentType() == SegmentType::ChordRest) {
    1825            8 :                         const auto annotations = segment->annotations(); // make a copy since we alter the list
    1826            8 :                         for (EngravingItem* a : annotations) {
    1827            0 :                             if (a->track() == trk) {
    1828            0 :                                 s->undoRemoveElement(a);
    1829              :                             }
    1830              :                         }
    1831            8 :                         EngravingItem* e = segment->element(trk);
    1832            8 :                         if (e && e->isChordRest()) {
    1833            2 :                             ChordRest* cr = toChordRest(e);
    1834            2 :                             if (cr->durationType() == DurationType::V_MEASURE) {
    1835            0 :                                 Fraction actualTicks = cr->actualTicks();
    1836            0 :                                 n += actualTicks;
    1837            0 :                                 cr->setDurationType(TDuration(actualTicks));
    1838              :                             } else {
    1839            2 :                                 n += cr->actualTicks();
    1840              :                             }
    1841            2 :                             s->undoRemoveElement(e);
    1842            2 :                             if (n >= Fraction(0, 1)) {
    1843            1 :                                 break;
    1844              :                             }
    1845              :                         }
    1846            8 :                     } else if (segment->segmentType() == SegmentType::Breath) {
    1847            0 :                         EngravingItem* e = segment->element(trk);
    1848            0 :                         if (e) {
    1849            0 :                             s->undoRemoveElement(e);
    1850              :                         }
    1851              :                     }
    1852            7 :                     segment = pseg;
    1853              :                 }
    1854          160 :                 rFlag = true;
    1855              :             }
    1856          244 :             voice_idx_t voice = trk % VOICES;
    1857          244 :             if (appendRestsIfNecessary && (n > Fraction(0, 1)) && (rFlag || voice == 0)) {
    1858              :                 // add rest to measure
    1859            1 :                 Fraction rtick = tick() + nl - n;
    1860            1 :                 track_idx_t track = staffIdx * VOICES + voice;
    1861            1 :                 s->setRest(rtick, track, n * stretch, false, 0, false);
    1862              :             }
    1863              :         }
    1864              :     }
    1865           57 :     if (diff < Fraction(0, 1)) {
    1866              :         //
    1867              :         //  CHECK: do not remove all slurs
    1868              :         //
    1869           36 :         for (EngravingItem* e : m->el()) {
    1870            0 :             if (e->isSlur()) {
    1871            0 :                 s->undoRemoveElement(e);
    1872              :             }
    1873              :         }
    1874              :     }
    1875              : 
    1876           57 :     Selection& sel = score()->selection();
    1877           57 :     if (!sel.isRange()) {
    1878           57 :         return;
    1879              :     }
    1880              :     // If the selection started and/or ended inside this measure, we should pass it
    1881              :     // updated start/end segments...
    1882            0 :     const Segment* oldStart = sel.startSegment();
    1883            0 :     if (oldStart && sel.startMeasureBase() == this) {
    1884            0 :         Segment* newStart = this->tick2segment(oldStart->tick());
    1885            0 :         sel.setStartSegment(newStart ? newStart : first());
    1886              :     }
    1887            0 :     const Segment* oldEnd = sel.endSegment();
    1888            0 :     if (oldEnd && sel.endMeasureBase() == this) {
    1889            0 :         Segment* newEnd = this->tick2segment(oldEnd->tick());
    1890            0 :         sel.setEndSegment(newEnd ? newEnd : last()->next1());
    1891              :     }
    1892           57 : }
    1893              : 
    1894              : //---------------------------------------------------------
    1895              : //   visible
    1896              : //---------------------------------------------------------
    1897              : 
    1898        78126 : bool Measure::visible(staff_idx_t staffIdx) const
    1899              : {
    1900        78126 :     if (staffIdx >= score()->staves().size()) {
    1901            0 :         LOGD("Measure::visible: bad staffIdx: %zu", staffIdx);
    1902            0 :         return false;
    1903              :     }
    1904        78126 :     if (system() && (system()->staves().empty() || !system()->staff(staffIdx)->show())) {
    1905         1153 :         return false;
    1906              :     }
    1907        76973 :     if (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx)) {
    1908            0 :         return false;
    1909              :     }
    1910        76973 :     return score()->staff(staffIdx)->show() && m_mstaves[staffIdx]->visible();
    1911              : }
    1912              : 
    1913              : //---------------------------------------------------------
    1914              : //   stemless
    1915              : //---------------------------------------------------------
    1916              : 
    1917      2685616 : bool Measure::stemless(staff_idx_t staffIdx) const
    1918              : {
    1919      2685616 :     const Staff* staff = score()->staff(staffIdx);
    1920      2685616 :     if (!staff) {
    1921           15 :         return false;
    1922              :     }
    1923              : 
    1924      2685601 :     return staff->stemless(tick()) || m_mstaves[staffIdx]->stemless() || staff->staffType(tick())->stemless();
    1925              : }
    1926              : 
    1927              : //---------------------------------------------------------
    1928              : //   isFinalMeasureOfSection
    1929              : //    returns true if this measure is final actual measure of a section
    1930              : //    takes into consideration fact that subsequent measures base objects
    1931              : //    may have section break before encountering next actual measure
    1932              : //---------------------------------------------------------
    1933              : 
    1934            0 : bool Measure::isFinalMeasureOfSection() const
    1935              : {
    1936            0 :     const MeasureBase* mb = static_cast<const MeasureBase*>(this);
    1937              : 
    1938              :     do {
    1939            0 :         if (mb->sectionBreak()) {
    1940            0 :             return true;
    1941              :         }
    1942              : 
    1943            0 :         mb = mb->next();
    1944            0 :     } while (mb && !mb->isMeasure());           // loop until reach next actual measure or end of score
    1945              : 
    1946            0 :     return false;
    1947              : }
    1948              : 
    1949       191121 : LayoutBreak* Measure::sectionBreakElement(bool includeNextFrames) const
    1950              : {
    1951       191121 :     const MeasureBase* mb = static_cast<const MeasureBase*>(this);
    1952              : 
    1953              :     do {
    1954       192287 :         if (LayoutBreak* sectionBreak = mb->sectionBreakElement()) {
    1955          373 :             return sectionBreak;
    1956              :         }
    1957              : 
    1958       191914 :         mb = mb->next();
    1959       191914 :     } while (includeNextFrames && mb && !mb->isMeasure());           // loop until reach next actual measure or end of score
    1960              : 
    1961       190748 :     return nullptr;
    1962              : }
    1963              : 
    1964              : //---------------------------------------------------------
    1965              : //   isAnacrusis
    1966              : //---------------------------------------------------------
    1967              : 
    1968        78036 : bool Measure::isAnacrusis() const
    1969              : {
    1970        78036 :     const MeasureBase* pm = prev();
    1971              : 
    1972        78036 :     if (excludeFromNumbering() || !pm || pm->isBox() || pm->lineBreak() || pm->pageBreak() || pm->sectionBreak()) {
    1973        26456 :         if (timesig() - ticks() > Fraction(0, 1)) {
    1974           27 :             return true;
    1975              :         }
    1976              :     }
    1977        78009 :     return false;
    1978              : }
    1979              : 
    1980              : //---------------------------------------------------------
    1981              : //   isFirstInSystem
    1982              : //---------------------------------------------------------
    1983              : 
    1984       575602 : bool Measure::isFirstInSystem() const
    1985              : {
    1986       575602 :     IF_ASSERT_FAILED(system()) {
    1987            0 :         return false;
    1988              :     }
    1989       575602 :     return system()->firstMeasure() == this;
    1990              : }
    1991              : 
    1992       169555 : bool Measure::isLastInSystem() const
    1993              : {
    1994       169555 :     IF_ASSERT_FAILED(system()) {
    1995            0 :         return false;
    1996              :     }
    1997       169555 :     return system()->lastMeasure() == this;
    1998              : }
    1999              : 
    2000              : //---------------------------------------------------------
    2001              : //   isFirstInSection
    2002              : //---------------------------------------------------------
    2003              : 
    2004       141898 : bool Measure::isFirstInSection() const
    2005              : {
    2006       152932 :     for (MeasureBase* m = prev(); m; m = m->prev()) {
    2007       134309 :         if (m->sectionBreak()) {
    2008          207 :             return true;
    2009       134102 :         } else if (m->isMeasure()) {
    2010       123068 :             return false;
    2011              :         }
    2012              :     }
    2013        18623 :     return true;
    2014              : }
    2015              : 
    2016              : //---------------------------------------------------------
    2017              : //   scanElements
    2018              : //---------------------------------------------------------
    2019              : 
    2020         3313 : void Measure::scanElements(std::function<void(EngravingItem*)> func)
    2021              : {
    2022         3313 :     size_t nstaves = score()->nstaves();
    2023         3313 :     if (nstaves == 0) {
    2024           64 :         return;
    2025              :     }
    2026              : 
    2027         3249 :     MeasureBase::scanElements(func);
    2028              : 
    2029         7174 :     for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
    2030         3925 :         MStaff* ms = m_mstaves[staffIdx];
    2031         3925 :         MeasureNumber* measureNumber = ms->measureNumber();
    2032         3925 :         if (measureNumber && measureNumber->systemFlag() && showMeasureNumberOnStaff(staffIdx)) {
    2033          343 :             func(measureNumber);
    2034              :         }
    2035              : 
    2036         3925 :         if (!(visible(staffIdx) && score()->staff(staffIdx)->show()) && !isCutawayClef(staffIdx)) {
    2037           91 :             continue;
    2038              :         }
    2039              : 
    2040         3834 :         if (measureNumber && !measureNumber->systemFlag()) {
    2041            0 :             func(measureNumber);
    2042              :         }
    2043              : 
    2044         3834 :         func(ms->lines());
    2045         3834 :         if (ms->vspacerUp()) {
    2046            0 :             func(ms->vspacerUp());
    2047              :         }
    2048         3834 :         if (ms->vspacerDown()) {
    2049            0 :             func(ms->vspacerDown());
    2050              :         }
    2051              : 
    2052         3834 :         if (ms->mmRangeText()) {
    2053            0 :             func(ms->mmRangeText());
    2054              :         }
    2055              :     }
    2056              : 
    2057        13141 :     for (Segment* s = first(); s; s = s->next()) {
    2058         9892 :         if (!s->enabled()) {
    2059           83 :             continue;
    2060              :         }
    2061         9809 :         s->scanElements(func);
    2062              :     }
    2063              : }
    2064              : 
    2065              : //---------------------------------------------------------
    2066              : //   connectTremolo
    2067              : ///   Connect two-notes tremolo and update duration types
    2068              : ///   for the involved chords.
    2069              : //---------------------------------------------------------
    2070              : 
    2071        46284 : void Measure::connectTremolo()
    2072              : {
    2073        46284 :     const size_t ntracks = score()->ntracks();
    2074        46284 :     constexpr SegmentType st = SegmentType::ChordRest;
    2075       140603 :     for (Segment* s = first(st); s; s = s->next(st)) {
    2076       776083 :         for (track_idx_t i = 0; i < ntracks; ++i) {
    2077       681764 :             EngravingItem* e = s->element(i);
    2078       681764 :             if (!e || !e->isChord()) {
    2079       608213 :                 continue;
    2080              :             }
    2081              : 
    2082        73551 :             Chord* c = toChord(e);
    2083        73551 :             TremoloTwoChord* tremolo = c->tremoloTwoChord();
    2084        73551 :             if (tremolo) {
    2085              :                 // Ensure correct duration type for chord
    2086          264 :                 c->setDurationType(tremolo->durationType());
    2087              : 
    2088              :                 // If it is the first tremolo's chord, find the second
    2089              :                 // chord for tremolo, if needed.
    2090          264 :                 if (!tremolo->chord1()) {
    2091           32 :                     tremolo->setChords(c, tremolo->chord2());
    2092          232 :                 } else if (tremolo->chord1() != c || tremolo->chord2()) {
    2093          229 :                     continue;
    2094              :                 }
    2095              : 
    2096           35 :                 for (Segment* ls = s->next(st); ls; ls = ls->next(st)) {
    2097           35 :                     if (EngravingItem* element = ls->element(i)) {
    2098           35 :                         if (!element->isChord()) {
    2099            0 :                             LOGD("cannot connect tremolo");
    2100            0 :                             continue;
    2101              :                         }
    2102           35 :                         Chord* nc = toChord(element);
    2103           35 :                         tremolo->setChords(c, nc);
    2104           35 :                         nc->setTremoloTwoChord(tremolo);
    2105           35 :                         break;
    2106              :                     }
    2107              :                 }
    2108              : 
    2109           35 :                 if (!tremolo->chord2()) {
    2110              :                     // this is an invalid tremolo! a continued tremolo was started on one note without a valid next note in that measure
    2111              :                     // remove the tremolo entirely
    2112            0 :                     c->setTremoloTwoChord(nullptr);
    2113            0 :                     score()->removeElement(tremolo);
    2114              :                 }
    2115              :             }
    2116              :         }
    2117              :     }
    2118        46284 : }
    2119              : 
    2120              : //---------------------------------------------------------
    2121              : //   createVoice
    2122              : //    Create a voice on demand by filling the measure
    2123              : //    with a whole measure rest.
    2124              : //    Check if there are any chord/rests in track; if
    2125              : //    not create a whole measure rest
    2126              : //---------------------------------------------------------
    2127              : 
    2128            0 : void Measure::createVoice(int track)
    2129              : {
    2130            0 :     for (Segment* s = first(); s; s = s->next()) {
    2131            0 :         if (s->segmentType() != SegmentType::ChordRest) {
    2132            0 :             continue;
    2133              :         }
    2134            0 :         if (s->element(track) == 0) {
    2135            0 :             score()->setRest(s->tick(), track, ticks(), true, 0);
    2136              :         }
    2137            0 :         break;
    2138              :     }
    2139            0 : }
    2140              : 
    2141              : //---------------------------------------------------------
    2142              : //   sortStaves
    2143              : //---------------------------------------------------------
    2144              : 
    2145            0 : void Measure::sortStaves(std::vector<staff_idx_t>& dst)
    2146              : {
    2147            0 :     std::vector<MStaff*> ms;
    2148            0 :     ms.reserve(dst.size());
    2149            0 :     for (staff_idx_t idx : dst) {
    2150            0 :         ms.push_back(m_mstaves[idx]);
    2151              :     }
    2152            0 :     m_mstaves = ms;
    2153              : 
    2154            0 :     for (staff_idx_t staffIdx = 0; staffIdx < m_mstaves.size(); ++staffIdx) {
    2155            0 :         m_mstaves[staffIdx]->lines()->setTrack(staffIdx * VOICES);
    2156              :     }
    2157            0 :     for (Segment& s : m_segments) {
    2158            0 :         s.sortStaves(dst);
    2159              :     }
    2160              : 
    2161            0 :     for (EngravingItem* e : el()) {
    2162            0 :         if (e->track() == muse::nidx || e->isTopSystemObject()) {
    2163            0 :             continue;
    2164              :         }
    2165            0 :         voice_idx_t voice    = e->voice();
    2166            0 :         staff_idx_t staffIdx = e->staffIdx();
    2167            0 :         staff_idx_t idx = muse::indexOf(dst, staffIdx);
    2168            0 :         e->setTrack(idx * VOICES + voice);
    2169              :     }
    2170              : 
    2171            0 :     score()->undoUpdatePlayCountText(this);
    2172            0 : }
    2173              : 
    2174              : //---------------------------------------------------------
    2175              : //   checkMultiVoices
    2176              : ///   Check for more than on voice in this measure and staff and
    2177              : ///   set MStaff->hasVoices
    2178              : //---------------------------------------------------------
    2179              : 
    2180         5776 : void Measure::checkMultiVoices(staff_idx_t staffIdx)
    2181              : {
    2182         5776 :     if (hasVoices(staffIdx, tick(), ticks())) {
    2183          937 :         m_mstaves[staffIdx]->setHasVoices(true);
    2184              :     } else {
    2185         4839 :         m_mstaves[staffIdx]->setHasVoices(false);
    2186              :     }
    2187         5776 : }
    2188              : 
    2189              : //---------------------------------------------------------
    2190              : //   hasVoices
    2191              : //---------------------------------------------------------
    2192              : 
    2193       127684 : bool Measure::hasVoices(staff_idx_t staffIdx, Fraction stick, Fraction len, bool considerInvisible) const
    2194              : {
    2195       127684 :     Staff* st = score()->staff(staffIdx);
    2196       127684 :     if (st->isTabStaff(stick)) {
    2197              :         // TODO: tab staves use different rules for stem direction etc
    2198              :         // see for example https://musescore.org/en/node/308371
    2199              :         // we should consider coming up with a more comprehensive solution
    2200              :         // but for now, we are forcing measures on tab staves to be consider as a whole -
    2201              :         // either they have voices or not
    2202              :         // (rather than checking tick ranges)
    2203         1974 :         stick = tick();
    2204         1974 :         len = stretchedLen(st);
    2205              :     }
    2206              : 
    2207       127684 :     track_idx_t strack = staffIdx * VOICES + 1;
    2208       127684 :     track_idx_t etrack = staffIdx * VOICES + VOICES;
    2209       127684 :     Fraction etick = stick + len;
    2210              : 
    2211       433925 :     for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
    2212       355108 :         if (s->tick() >= etick) {
    2213        38483 :             break;
    2214              :         }
    2215      1236489 :         for (track_idx_t track = strack; track < etrack; ++track) {
    2216       930248 :             ChordRest* cr = toChordRest(s->element(track));
    2217       930248 :             if (cr) {
    2218        26812 :                 if (cr->endTick() <= stick) {
    2219        15880 :                     continue;
    2220              :                 }
    2221        10932 :                 if (considerInvisible) {
    2222         1098 :                     return true;
    2223              :                 }
    2224         9834 :                 bool v = false;
    2225         9834 :                 if (cr->isChord()) {
    2226         7927 :                     Chord* c = toChord(cr);
    2227              : 
    2228              :                     // consider a chord visible if stem, hook(s) or beam(s) are visible
    2229        15513 :                     if ((c->stem() && c->stem()->visible())
    2230          357 :                         || (c->hook() && c->hook()->visible())
    2231        15854 :                         || (c->beam() && c->beam()->visible())) {
    2232         7570 :                         v = true;
    2233              :                     } else {
    2234              :                         // or any of its notes
    2235          373 :                         for (Note* n : c->notes()) {
    2236          357 :                             if (n->visible()) {
    2237          341 :                                 v = true;
    2238          341 :                                 break;
    2239              :                             }
    2240              :                         }
    2241              :                     }
    2242         1907 :                 } else if (cr->isRest()) {
    2243         1907 :                     v = cr->visible() && !toRest(cr)->isGap();
    2244              :                 }
    2245         9834 :                 if (v) {
    2246         9286 :                     return true;
    2247              :                 }
    2248              :             }
    2249              :         }
    2250              :     }
    2251       117300 :     return false;
    2252              : }
    2253              : 
    2254              : //---------------------------------------------------------
    2255              : //   hasVoice
    2256              : //---------------------------------------------------------
    2257              : 
    2258         3714 : bool Measure::hasVoice(track_idx_t track) const
    2259              : {
    2260         3714 :     if (track >= score()->ntracks()) {
    2261            0 :         return false;
    2262              :     }
    2263        20628 :     for (Segment* s = first(); s; s = s->next()) {
    2264        17742 :         if (s->segmentType() != SegmentType::ChordRest) {
    2265         6972 :             continue;
    2266              :         }
    2267        10770 :         if (s->element(track)) {
    2268          828 :             return true;
    2269              :         }
    2270              :     }
    2271         2886 :     return false;
    2272              : }
    2273              : 
    2274              : //-------------------------------------------------------------------
    2275              : //   isEmpty
    2276              : ///   Check if the measure is filled by a full-measure rest, or is
    2277              : ///   full of rests on this staff, that may have fermatas on them.
    2278              : ///   If staff is -1, then check for all staves.
    2279              : //-------------------------------------------------------------------
    2280              : 
    2281         1639 : bool Measure::isEmpty(staff_idx_t staffIdx) const
    2282              : {
    2283         1639 :     if (isMMRest()) {
    2284            0 :         return true;
    2285              :     }
    2286         1639 :     track_idx_t strack = 0;
    2287         1639 :     track_idx_t etrack = 0;
    2288         1639 :     if (staffIdx == muse::nidx) {
    2289            0 :         strack = 0;
    2290            0 :         etrack = score()->nstaves() * VOICES;
    2291              :     } else {
    2292         1639 :         strack = staffIdx * VOICES;
    2293         1639 :         etrack = strack + VOICES;
    2294              :     }
    2295         1639 :     if (isMeasureRepeatGroup(staffIdx)) {
    2296            0 :         return false;
    2297              :     }
    2298         3320 :     for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
    2299         8485 :         for (track_idx_t track = strack; track < etrack; ++track) {
    2300         6800 :             EngravingItem* e = s->element(track);
    2301         6800 :             if (e && !e->isRest()) {
    2302           60 :                 return false;
    2303              :             }
    2304              :             // Check for cross-staff chords
    2305         6740 :             bool hasStaves = score()->staff(track / VOICES)->part()->staves().size() > 1;
    2306         6740 :             if (hasStaves) {
    2307         6544 :                 if (strack >= VOICES) {
    2308         4248 :                     e = s->element(track - VOICES);
    2309         4248 :                     if (e && !e->isRest() && e->vStaffIdx() == staffIdx) {
    2310            0 :                         return false;
    2311              :                     }
    2312              :                 }
    2313         6544 :                 if (etrack < score()->nstaves() * VOICES) {
    2314         6508 :                     e = s->element(track + VOICES);
    2315         6508 :                     if (e && !e->isRest() && e->vStaffIdx() == staffIdx) {
    2316            0 :                         return false;
    2317              :                     }
    2318              :                 }
    2319              :             }
    2320              :         }
    2321         1711 :         for (EngravingItem* a : s->annotations()) {
    2322           30 :             if (a && staffIdx == muse::nidx) {
    2323            4 :                 return false;
    2324              :             }
    2325           30 :             if (!a || a->systemFlag() || !a->visible() || a->isFermata()) {
    2326            0 :                 continue;
    2327              :             }
    2328           30 :             size_t atrack = a->track();
    2329           30 :             if (atrack >= strack && atrack < etrack) {
    2330            4 :                 return false;
    2331              :             }
    2332              :         }
    2333              :     }
    2334         1575 :     return true;
    2335              : }
    2336              : 
    2337              : //---------------------------------------------------------
    2338              : //   isCutawayClef
    2339              : ///    Check for empty measure with only
    2340              : ///    a Courtesy Clef before End Bar Line
    2341              : //---------------------------------------------------------
    2342              : 
    2343        44658 : bool Measure::isCutawayClef(staff_idx_t staffIdx) const
    2344              : {
    2345        44658 :     if (!score()->staff(staffIdx) || !m_mstaves[staffIdx]) {
    2346            0 :         return false;
    2347              :     }
    2348        44658 :     bool empty = (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx)) || !m_mstaves[staffIdx]->visible();
    2349        44658 :     if (!empty) {
    2350        44658 :         return false;
    2351              :     }
    2352              :     track_idx_t strack;
    2353              :     track_idx_t etrack;
    2354            0 :     if (staffIdx == muse::nidx) {
    2355            0 :         strack = 0;
    2356            0 :         etrack = score()->nstaves() * VOICES;
    2357              :     } else {
    2358            0 :         strack = staffIdx * VOICES;
    2359            0 :         etrack = strack + VOICES;
    2360              :     }
    2361              :     // find segment before EndBarLine
    2362            0 :     Segment* s = nullptr;
    2363            0 :     for (Segment* ls = last(); ls; ls = ls->prev()) {
    2364            0 :         if (ls->segmentType() == SegmentType::EndBarLine) {
    2365            0 :             s = ls->prev();
    2366            0 :             break;
    2367              :         }
    2368              :     }
    2369            0 :     while (s && (s->isTimeTickType() || s->isBreathType())) {
    2370            0 :         s = s->prev();
    2371              :     }
    2372            0 :     if (!s) {
    2373            0 :         return false;
    2374              :     }
    2375            0 :     for (track_idx_t track = strack; track < etrack; ++track) {
    2376            0 :         EngravingItem* e = s->element(track);
    2377            0 :         if (!e || !e->isClef()) {
    2378            0 :             continue;
    2379              :         }
    2380            0 :         if ((nextMeasure() && (nextMeasure()->system() == system())) || toClef(e)->showCourtesy()) {
    2381            0 :             return true;
    2382              :         }
    2383              :     }
    2384            0 :     return false;
    2385              : }
    2386              : 
    2387              : //---------------------------------------------------------
    2388              : //   isFullMeasureRest
    2389              : //    Check for an empty measure, filled with full measure
    2390              : //    rests.
    2391              : //---------------------------------------------------------
    2392              : 
    2393           55 : bool Measure::isFullMeasureRest() const
    2394              : {
    2395           55 :     track_idx_t strack = 0;
    2396           55 :     track_idx_t etrack = score()->nstaves() * VOICES;
    2397              : 
    2398           55 :     Segment* s = first(SegmentType::ChordRest);
    2399          243 :     for (track_idx_t track = strack; track < etrack; ++track) {
    2400          208 :         EngravingItem* e = s->element(track);
    2401          208 :         if (e) {
    2402           67 :             if (!e->isRest()) {
    2403           19 :                 return false;
    2404              :             }
    2405           48 :             Rest* rest = toRest(e);
    2406           48 :             if (rest->durationType().type() != DurationType::V_MEASURE) {
    2407            1 :                 return false;
    2408              :             }
    2409              :         }
    2410              :     }
    2411           35 :     return true;
    2412              : }
    2413              : 
    2414              : //---------------------------------------------------------
    2415              : //   isEmpty
    2416              : //---------------------------------------------------------
    2417              : 
    2418            0 : bool Measure::empty() const
    2419              : {
    2420            0 :     if (excludeFromNumbering()) {
    2421            0 :         return false;
    2422              :     }
    2423            0 :     int n = 0;
    2424            0 :     track_idx_t tracks = m_mstaves.size() * VOICES;
    2425              :     static const SegmentType st = SegmentType::ChordRest;
    2426            0 :     for (const Segment* s = first(st); s; s = s->next(st)) {
    2427            0 :         bool restFound = false;
    2428            0 :         for (track_idx_t track = 0; track < tracks; ++track) {
    2429            0 :             if ((track % VOICES) == 0 && !score()->staff(track / VOICES)->show()) {
    2430            0 :                 track += VOICES - 1;
    2431            0 :                 continue;
    2432              :             }
    2433            0 :             if (s->element(track)) {
    2434            0 :                 if (!s->element(track)->isRest()) {
    2435            0 :                     return false;
    2436              :                 }
    2437            0 :                 restFound = true;
    2438              :             }
    2439              :         }
    2440            0 :         if (restFound) {
    2441            0 :             ++n;
    2442              :         }
    2443              :         // measure is not empty if there is more than one rest
    2444            0 :         if (n > 1) {
    2445            0 :             return false;
    2446              :         }
    2447              :     }
    2448            0 :     return true;
    2449              : }
    2450              : 
    2451              : //---------------------------------------------------------
    2452              : //   isOnlyRests
    2453              : //---------------------------------------------------------
    2454              : 
    2455           38 : bool Measure::isOnlyRests(track_idx_t track) const
    2456              : {
    2457              :     static const SegmentType st = SegmentType::ChordRest;
    2458           95 :     for (const Segment* s = first(st); s; s = s->next(st)) {
    2459           67 :         if (s->segmentType() != st || !s->element(track)) {
    2460           41 :             continue;
    2461              :         }
    2462           26 :         if (!s->element(track)->isRest()) {
    2463           10 :             return false;
    2464              :         }
    2465              :     }
    2466           28 :     return true;
    2467              : }
    2468              : 
    2469              : //---------------------------------------------------------
    2470              : //   isOnlyGapRests
    2471              : //---------------------------------------------------------
    2472              : 
    2473            7 : bool Measure::isOnlyGapRests(track_idx_t track) const
    2474              : {
    2475              :     static const SegmentType st { SegmentType::ChordRest };
    2476            9 :     for (const Segment* s = first(st); s; s = s->next(st)) {
    2477            9 :         if (s->segmentType() != st || !s->element(track)) {
    2478            0 :             continue;
    2479              :         }
    2480            9 :         if (!s->element(track)->isRest() || !toRest(s->element(track))->isGap()) {
    2481            7 :             return false;
    2482              :         }
    2483              :     }
    2484            0 :     return true;
    2485              : }
    2486              : 
    2487              : //---------------------------------------------------------
    2488              : //   stretchedLen
    2489              : //---------------------------------------------------------
    2490              : 
    2491         3988 : Fraction Measure::stretchedLen(const Staff* staff) const
    2492              : {
    2493         3988 :     return ticks() * staff->timeStretch(tick());
    2494              : }
    2495              : 
    2496              : //---------------------------------------------------------
    2497              : //   cloneMeasure
    2498              : //---------------------------------------------------------
    2499              : 
    2500            0 : Measure* Measure::cloneMeasure(Score* sc, const Fraction& tick, TieMap* tieMap)
    2501              : {
    2502            0 :     Measure* m      = new Measure(sc);
    2503            0 :     m->m_timesig    = m_timesig;
    2504            0 :     m->m_len         = m_len;
    2505            0 :     m->m_repeatCount = m_repeatCount;
    2506              : 
    2507            0 :     assert(sc->staves().size() >= m_mstaves.size());   // destination score we're cloning into must have at least as many staves as measure being cloned
    2508              : 
    2509            0 :     m->setMeasureNumber(measureNumber());
    2510            0 :     m->setMeasureNumberOffset(measureNumberOffset());
    2511            0 :     m->setExcludeFromNumbering(excludeFromNumbering());
    2512            0 :     m->m_userStretch           = m_userStretch;
    2513            0 :     m->m_breakMultiMeasureRest = m_breakMultiMeasureRest;
    2514            0 :     m->m_playbackCount         = m_playbackCount;
    2515              : 
    2516            0 :     m->setTick(tick);
    2517            0 :     m->setLineBreak(lineBreak());
    2518            0 :     m->setPageBreak(pageBreak());
    2519            0 :     m->setSectionBreak(sectionBreak());
    2520              : 
    2521            0 :     m->setHeader(header());
    2522            0 :     m->setTrailer(trailer());
    2523              : 
    2524            0 :     size_t tracks = sc->nstaves() * VOICES;
    2525            0 :     TupletMap tupletMap;
    2526              : 
    2527            0 :     for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
    2528            0 :         Segment* s = Factory::createSegment(m, oseg->segmentType(), oseg->rtick());
    2529            0 :         s->setEnabled(oseg->enabled());
    2530            0 :         s->setVisible(oseg->visible());
    2531            0 :         s->setHeader(oseg->header());
    2532            0 :         s->setTrailer(oseg->trailer());
    2533              : 
    2534            0 :         m->m_segments.push_back(s);
    2535            0 :         for (track_idx_t track = 0; track < tracks; ++track) {
    2536            0 :             EngravingItem* oe = oseg->element(track);
    2537            0 :             for (EngravingItem* e : oseg->annotations()) {
    2538            0 :                 if (e->generated() || e->track() != track) {
    2539            0 :                     continue;
    2540              :                 }
    2541            0 :                 EngravingItem* ne = e->clone();
    2542            0 :                 ne->setTrack(track);
    2543            0 :                 ne->setOffset(e->offset());
    2544            0 :                 ne->setScore(sc);
    2545            0 :                 s->add(ne);
    2546              :             }
    2547            0 :             if (!oe) {
    2548            0 :                 continue;
    2549              :             }
    2550            0 :             EngravingItem* ne = oe->clone();
    2551            0 :             if (oe->isChordRest()) {
    2552            0 :                 ChordRest* ocr = toChordRest(oe);
    2553            0 :                 ChordRest* ncr = toChordRest(ne);
    2554            0 :                 Tuplet* ot     = ocr->tuplet();
    2555            0 :                 if (ot) {
    2556            0 :                     Tuplet* nt = tupletMap.findNew(ot);
    2557            0 :                     if (nt == 0) {
    2558            0 :                         nt = Factory::copyTuplet(*ot);
    2559            0 :                         nt->clear();
    2560            0 :                         nt->setTrack(track);
    2561            0 :                         nt->setScore(sc);
    2562            0 :                         nt->setOwnershipParent(m);
    2563            0 :                         nt->setTick(m->tick() + ot->rtick());
    2564            0 :                         tupletMap.add(ot, nt);
    2565              :                     }
    2566            0 :                     ncr->setTuplet(nt);
    2567            0 :                     nt->add(ncr);
    2568              :                 }
    2569            0 :                 if (oe->isChord()) {
    2570            0 :                     Chord* och = toChord(ocr);
    2571            0 :                     Chord* nch = toChord(ncr);
    2572            0 :                     size_t n = och->notes().size();
    2573            0 :                     for (size_t i = 0; i < n; ++i) {
    2574            0 :                         Note* on = och->notes().at(i);
    2575            0 :                         Note* nn = nch->notes().at(i);
    2576            0 :                         if (on->tieFor()) {
    2577            0 :                             Tie* tie = on->tieFor()->clone();
    2578            0 :                             tie->setScore(sc);
    2579            0 :                             nn->setTieFor(tie);
    2580            0 :                             tie->setStartNote(nn);
    2581            0 :                             tieMap->add(on->tieFor(), tie);
    2582              :                         }
    2583            0 :                         if (on->tieBack()) {
    2584            0 :                             Tie* tie = tieMap->findNew(on->tieBack());
    2585            0 :                             if (tie) {
    2586            0 :                                 nn->setTieBack(tie);
    2587            0 :                                 tie->setEndNote(nn);
    2588              :                             } else {
    2589            0 :                                 LOGD("cloneMeasure: cannot find tie, track %zu", track);
    2590              :                             }
    2591              :                         }
    2592              :                     }
    2593              :                 }
    2594              :             }
    2595            0 :             ne->setOffset(oe->offset());
    2596            0 :             ne->setScore(sc);
    2597            0 :             s->add(ne);
    2598              :         }
    2599              :     }
    2600            0 :     for (EngravingItem* e : el()) {
    2601            0 :         EngravingItem* ne = e->clone();
    2602            0 :         ne->setScore(sc);
    2603            0 :         ne->setOffset(e->offset());
    2604            0 :         m->add(ne);
    2605              :     }
    2606            0 :     return m;
    2607            0 : }
    2608              : 
    2609              : //---------------------------------------------------------
    2610              : //   snap
    2611              : //---------------------------------------------------------
    2612              : 
    2613            0 : Fraction Measure::snap(const Fraction& tick, const PointF p) const
    2614              : {
    2615            0 :     Segment* s = first();
    2616            0 :     for (; s->next(); s = s->next()) {
    2617            0 :         double x  = s->x();
    2618            0 :         double dx = s->next()->x() - x;
    2619            0 :         if (s->tick() == tick) {
    2620            0 :             x += dx / 3.0 * 2.0;
    2621            0 :         } else if (s->next()->tick() == tick) {
    2622            0 :             x += dx / 3.0;
    2623              :         } else {
    2624            0 :             x += dx * .5;
    2625              :         }
    2626            0 :         if (p.x() < x) {
    2627            0 :             break;
    2628              :         }
    2629              :     }
    2630            0 :     return s->tick();
    2631              : }
    2632              : 
    2633              : //---------------------------------------------------------
    2634              : //   snapNote
    2635              : //---------------------------------------------------------
    2636              : 
    2637            0 : Fraction Measure::snapNote(const Fraction& /*tick*/, const PointF p, int staff) const
    2638              : {
    2639            0 :     Segment* s = first();
    2640              :     for (;;) {
    2641            0 :         Segment* ns = s->next();
    2642            0 :         while (ns && ns->element(staff) == 0) {
    2643            0 :             ns = ns->next();
    2644              :         }
    2645            0 :         if (ns == 0) {
    2646            0 :             break;
    2647              :         }
    2648            0 :         double x  = s->x();
    2649            0 :         double nx = x + (ns->x() - x) * .5;
    2650            0 :         if (p.x() < nx) {
    2651            0 :             break;
    2652              :         }
    2653            0 :         s = ns;
    2654            0 :     }
    2655            0 :     return s->tick();
    2656              : }
    2657              : 
    2658              : //---------------------------------------------------------
    2659              : //   searchSegment
    2660              : ///   Finds a segment which x position is most close to the
    2661              : ///   given \p x.
    2662              : ///   \param x The x coordinate in measure coordinates.
    2663              : ///   \param st Type of segments to search.
    2664              : ///   \param strack start of track range (strack included)
    2665              : ///   in which the found segment should contain elements.
    2666              : ///   \param etrack end of track range (etrack excluded)
    2667              : ///   in which the found segment should contain elements.
    2668              : ///   \param preferredSegment If not nullptr, will give
    2669              : ///   more space to the given segment when searching it by
    2670              : ///   coordinate.
    2671              : ///   \returns The segment that was found.
    2672              : //---------------------------------------------------------
    2673              : 
    2674            0 : Segment* Measure::searchSegment(double x, SegmentType st, track_idx_t strack, track_idx_t etrack, const Segment* preferredSegment,
    2675              :                                 double spacingFactor) const
    2676              : {
    2677            0 :     const track_idx_t lastTrack = etrack - 1;
    2678            0 :     for (Segment* segment = first(st); segment; segment = segment->next(st)) {
    2679            0 :         if (!segment->hasElements(strack, lastTrack)) {
    2680            0 :             continue;
    2681              :         }
    2682            0 :         if (segment->isTimeTickType() && segment->rtick() == ticks()) {
    2683            0 :             continue;
    2684              :         }
    2685            0 :         Segment* ns = segment->next(st);
    2686            0 :         for (; ns; ns = ns->next(st)) {
    2687            0 :             if (ns->hasElements(strack, lastTrack)) {
    2688            0 :                 break;
    2689              :             }
    2690              :         }
    2691            0 :         if (!ns) {
    2692            0 :             return segment;
    2693              :         }
    2694            0 :         if (preferredSegment == segment) {
    2695            0 :             if (x < (segment->x() + (ns->x() - segment->x()))) {
    2696            0 :                 return segment;
    2697              :             }
    2698            0 :         } else if (preferredSegment == ns) {
    2699            0 :             if (x <= segment->x()) {
    2700            0 :                 return segment;
    2701              :             }
    2702              :         } else {
    2703            0 :             if (x < (segment->x() + (ns->x() - segment->x()) * spacingFactor)) {
    2704            0 :                 return segment;
    2705              :             }
    2706              :         }
    2707              :     }
    2708            0 :     return nullptr;
    2709              : }
    2710              : 
    2711              : //---------------------------------------------------------
    2712              : //   getProperty
    2713              : //---------------------------------------------------------
    2714              : 
    2715        60924 : PropertyValue Measure::getProperty(Pid propertyId) const
    2716              : {
    2717        60924 :     switch (propertyId) {
    2718           25 :     case Pid::TIMESIG_NOMINAL:
    2719           25 :         return PropertyValue::fromValue(m_timesig);
    2720           14 :     case Pid::TIMESIG_ACTUAL:
    2721           14 :         return PropertyValue::fromValue(m_len);
    2722        11954 :     case Pid::EXCLUDE_FROM_NUMBERING:
    2723        11954 :         return excludeFromNumbering();
    2724        11954 :     case Pid::MEASURE_NUMBER_OFFSET:
    2725        11954 :         return measureNumberOffset();
    2726        11954 :     case Pid::MEASURE_NUMBER_MODE:
    2727        11954 :         return int(measureNumberMode());
    2728        11962 :     case Pid::BREAK_MMR:
    2729        11962 :         return breakMultiMeasureRest();
    2730            2 :     case Pid::REPEAT_COUNT:
    2731            2 :         return repeatCount();
    2732        11952 :     case Pid::USER_STRETCH:
    2733        11952 :         return userStretch();
    2734           36 :     case Pid::REPEAT_END:
    2735           36 :         return repeatEnd();
    2736           70 :     case Pid::REPEAT_START:
    2737           70 :         return repeatStart();
    2738            2 :     case Pid::REPEAT_JUMP:
    2739            2 :         return repeatJump();
    2740          999 :     default:
    2741          999 :         return MeasureBase::getProperty(propertyId);
    2742              :     }
    2743              : }
    2744              : 
    2745              : //---------------------------------------------------------
    2746              : //   setProperty
    2747              : //---------------------------------------------------------
    2748              : 
    2749         6034 : bool Measure::setProperty(Pid propertyId, const PropertyValue& value)
    2750              : {
    2751         6034 :     switch (propertyId) {
    2752            3 :     case Pid::TIMESIG_NOMINAL:
    2753            3 :         m_timesig = value.value<Fraction>();
    2754            3 :         break;
    2755            3 :     case Pid::TIMESIG_ACTUAL:
    2756            3 :         m_len = value.value<Fraction>();
    2757            3 :         break;
    2758            0 :     case Pid::EXCLUDE_FROM_NUMBERING:
    2759            0 :         setExcludeFromNumbering(value.toBool());
    2760            0 :         triggerLayoutAll();
    2761            0 :         return true;
    2762            0 :     case Pid::MEASURE_NUMBER_OFFSET:
    2763            0 :         setMeasureNumberOffset(value.toInt());
    2764            0 :         triggerLayoutAll();
    2765            0 :         return true;
    2766            0 :     case Pid::MEASURE_NUMBER_MODE:
    2767            0 :         setMeasureNumberMode(MeasureNumberMode(value.toInt()));
    2768            0 :         break;
    2769            2 :     case Pid::BREAK_MMR:
    2770            2 :         setBreakMultiMeasureRest(value.toBool());
    2771            2 :         break;
    2772            0 :     case Pid::REPEAT_COUNT:
    2773            0 :         setRepeatCount(value.toInt());
    2774            0 :         score()->undoUpdatePlayCountText(this);
    2775            0 :         break;
    2776            0 :     case Pid::USER_STRETCH:
    2777            0 :         setUserStretch(value.toDouble());
    2778            0 :         break;
    2779            8 :     case Pid::REPEAT_END:
    2780            8 :         setRepeatEnd(value.toBool());
    2781            8 :         score()->invalidateRepeatList();
    2782            8 :         break;
    2783            5 :     case Pid::REPEAT_START:
    2784            5 :         setRepeatStart(value.toBool());
    2785            5 :         score()->invalidateRepeatList();
    2786            5 :         break;
    2787          244 :     case Pid::REPEAT_JUMP:
    2788          244 :         setRepeatJump(value.toBool());
    2789          244 :         score()->invalidateRepeatList();
    2790          244 :         break;
    2791         5769 :     default:
    2792         5769 :         return MeasureBase::setProperty(propertyId, value);
    2793              :     }
    2794          265 :     triggerLayout();
    2795          265 :     return true;
    2796              : }
    2797              : 
    2798              : //---------------------------------------------------------
    2799              : //   propertyDefault
    2800              : //---------------------------------------------------------
    2801              : 
    2802        60945 : PropertyValue Measure::propertyDefault(Pid propertyId) const
    2803              : {
    2804        60945 :     switch (propertyId) {
    2805            0 :     case Pid::TIMESIG_NOMINAL:
    2806              :     case Pid::TIMESIG_ACTUAL:
    2807            0 :         return PropertyValue();
    2808        11952 :     case Pid::EXCLUDE_FROM_NUMBERING:
    2809        11952 :         return false;
    2810        11952 :     case Pid::MEASURE_NUMBER_OFFSET:
    2811        11952 :         return 0;
    2812        11952 :     case Pid::MEASURE_NUMBER_MODE:
    2813        11952 :         return int(MeasureNumberMode::AUTO);
    2814        11952 :     case Pid::BREAK_MMR:
    2815        11952 :         return false;
    2816            0 :     case Pid::REPEAT_COUNT:
    2817            0 :         return 2;
    2818        11952 :     case Pid::USER_STRETCH:
    2819        11952 :         return 1.0;
    2820            0 :     case Pid::REPEAT_END:
    2821              :     case Pid::REPEAT_START:
    2822              :     case Pid::REPEAT_JUMP:
    2823            0 :         return false;
    2824         1185 :     default:
    2825         1185 :         break;
    2826              :     }
    2827         1185 :     return MeasureBase::propertyDefault(propertyId);
    2828              : }
    2829              : 
    2830              : //---------------------------------------------------------
    2831              : //   undoChangeProperty
    2832              : //---------------------------------------------------------
    2833              : 
    2834           49 : void Measure::undoChangeProperty(Pid id, const PropertyValue& v)
    2835              : {
    2836           49 :     undoChangeProperty(id, v, propertyFlags(id));
    2837           49 : }
    2838              : 
    2839           49 : void Measure::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps)
    2840              : {
    2841           49 :     if ((getProperty(id) == v) && (propertyFlags(id) == ps)) {
    2842           30 :         return;
    2843              :     }
    2844           19 :     if (id == Pid::REPEAT_START || id == Pid::REPEAT_END) {
    2845              :         // change also coresponding mmRestMeasure
    2846           11 :         Measure* m = const_cast<Measure*>(toMeasure(this)->coveringMMRestOrThis());
    2847           11 :         if (m != this) {
    2848            0 :             m->undoChangeProperty(id, v);
    2849              :         }
    2850              :     }
    2851           19 :     EngravingObject::undoChangeProperty(id, v, ps);
    2852              : }
    2853              : 
    2854              : //-------------------------------------------------------------------
    2855              : //   mmRestFirst
    2856              : //    this is a multi measure rest
    2857              : //    returns first measure of replaced sequence of empty measures
    2858              : //-------------------------------------------------------------------
    2859              : 
    2860          660 : Measure* Measure::mmRestFirst() const
    2861              : {
    2862          660 :     assert(isMMRest());
    2863          660 :     if (prev()) {
    2864          602 :         return toMeasure(prev()->next());
    2865              :     }
    2866           58 :     return score()->firstMeasure();
    2867              : }
    2868              : 
    2869              : //-------------------------------------------------------------------
    2870              : //   mmRestLast
    2871              : //    this is a multi measure rest
    2872              : //    returns last measure of replaced sequence of empty measures
    2873              : //-------------------------------------------------------------------
    2874              : 
    2875         4457 : Measure* Measure::mmRestLast() const
    2876              : {
    2877         4457 :     assert(isMMRest());
    2878         4457 :     if (next()) {
    2879         4288 :         return toMeasure(next()->prev());
    2880              :     }
    2881          169 :     return score()->lastMeasure();
    2882              : }
    2883              : 
    2884              : //---------------------------------------------------------
    2885              : //   coveringMMRestOrThis
    2886              : //    if multi-measure rests are enabled,
    2887              : //        and this measure is covered by an MMRest,
    2888              : //            return that MMRest.
    2889              : //    otherwise, return the measure itself.
    2890              : //---------------------------------------------------------
    2891              : 
    2892       468274 : Measure* Measure::coveringMMRestOrThis()
    2893              : {
    2894       468274 :     if (!style().styleB(Sid::createMultiMeasureRests)) {
    2895       460146 :         return this;
    2896              :     }
    2897              : 
    2898         8128 :     if (m_mmRest) {
    2899          735 :         return m_mmRest;
    2900              :     }
    2901              : 
    2902         7393 :     if (isMMRest()) {
    2903          231 :         return this;
    2904              :     }
    2905              : 
    2906         7162 :     const Measure* m = this;
    2907        60897 :     while (m && !m->m_mmRest) {
    2908        53735 :         m = m->prevMeasure();
    2909              :     }
    2910              : 
    2911         7162 :     if (m && !m->m_mmRest->mmRestLast()->isBefore(this)) {
    2912         1255 :         return m->m_mmRest;
    2913              :     }
    2914              : 
    2915         5907 :     return this;
    2916              : }
    2917              : 
    2918        24978 : const Measure* Measure::coveringMMRestOrThis() const
    2919              : {
    2920        24978 :     return const_cast<Measure*>(this)->coveringMMRestOrThis();
    2921              : }
    2922              : 
    2923       386536 : int Measure::measureRepeatCount(staff_idx_t staffIdx) const
    2924              : {
    2925       386536 :     if (staffIdx >= m_mstaves.size()) {
    2926            0 :         return 0;
    2927              :     }
    2928              : 
    2929       386536 :     return m_mstaves[staffIdx]->measureRepeatCount();
    2930              : }
    2931              : 
    2932           11 : bool Measure::containsMeasureRepeat(const staff_idx_t staffIdxFrom, const staff_idx_t staffIdxTo) const
    2933              : {
    2934           22 :     for (staff_idx_t idx = staffIdxFrom; idx <= staffIdxTo; ++idx) {
    2935           11 :         if (measureRepeatCount(idx) > 0) {
    2936            0 :             return true;
    2937              :         }
    2938              :     }
    2939              : 
    2940           11 :     return false;
    2941              : }
    2942              : 
    2943         4563 : void Measure::setMeasureRepeatCount(int n, staff_idx_t staffIdx)
    2944              : {
    2945         4563 :     if (staffIdx >= m_mstaves.size()) {
    2946            0 :         return;
    2947              :     }
    2948              : 
    2949         4563 :     m_mstaves[staffIdx]->setMeasureRepeatCount(n);
    2950              : }
    2951              : 
    2952        19348 : bool Measure::isMeasureRepeatGroup(staff_idx_t staffIdx) const
    2953              : {
    2954        19348 :     return measureRepeatCount(staffIdx) > 0;
    2955              : }
    2956              : 
    2957              : //---------------------------------------------------------
    2958              : //   isMeasureRepeatGroupWithNextM
    2959              : //    true if this and next measure are part of same MeasureRepeat group
    2960              : //---------------------------------------------------------
    2961              : 
    2962          118 : bool Measure::isMeasureRepeatGroupWithNextM(staff_idx_t staffIdx) const
    2963              : {
    2964          118 :     if (!isMeasureRepeatGroup(staffIdx) || !nextMeasure() || !nextMeasure()->isMeasureRepeatGroup(staffIdx)) {
    2965          112 :         return false;
    2966              :     }
    2967            6 :     if (measureRepeatCount(staffIdx) == nextMeasure()->measureRepeatCount(staffIdx) - 1) {
    2968            3 :         return true;
    2969              :     }
    2970            3 :     return false;
    2971              : }
    2972              : 
    2973              : //---------------------------------------------------------
    2974              : //   isMeasureRepeatGroupWithPrevM
    2975              : //    true if this and prev measure are part of same MeasureRepeat group
    2976              : //---------------------------------------------------------
    2977              : 
    2978          243 : bool Measure::isMeasureRepeatGroupWithPrevM(staff_idx_t staffIdx) const
    2979              : {
    2980          243 :     return measureRepeatCount(staffIdx) > 1;
    2981              : }
    2982              : 
    2983              : //---------------------------------------------------------
    2984              : //   firstMeasureOfGroup
    2985              : //    for measures within group containing MeasureRepeat,
    2986              : //    return the measure (possibly this) at start of group
    2987              : //---------------------------------------------------------
    2988              : 
    2989         3739 : Measure* Measure::firstOfMeasureRepeatGroup(staff_idx_t staffIdx) const
    2990              : {
    2991         3739 :     if (!isMeasureRepeatGroup(staffIdx)) {
    2992         3314 :         return nullptr;
    2993              :     }
    2994          425 :     Measure* m = const_cast<Measure*>(this);
    2995          589 :     for (int i = 1; i < measureRepeatCount(staffIdx); ++i) {
    2996          164 :         m = m->prevMeasure();
    2997              :     }
    2998          425 :     return m;
    2999              : }
    3000              : 
    3001              : //---------------------------------------------------------
    3002              : //   measureRepeatElement
    3003              : //    access MeasureRepeat element from anywhere in related group
    3004              : //---------------------------------------------------------
    3005              : 
    3006         3533 : MeasureRepeat* Measure::measureRepeatElement(staff_idx_t staffIdx) const
    3007              : {
    3008         3533 :     Measure* m = firstOfMeasureRepeatGroup(staffIdx);
    3009         3533 :     if (!m) {
    3010         3314 :         return nullptr;
    3011              :     }
    3012          306 :     while (m && m->isMeasureRepeatGroup(staffIdx)) {
    3013          306 :         track_idx_t strack = staff2track(staffIdx);
    3014          306 :         track_idx_t etrack = staff2track(staffIdx + 1);
    3015          654 :         for (track_idx_t track = strack; track < etrack; ++track) {
    3016              :             // should only be in first track, but just in case
    3017         1139 :             for (Segment* s = m->first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
    3018              :                 // should only be in first segment, but just in case
    3019          791 :                 EngravingItem* e = s->element(track);
    3020          791 :                 if (e && e->isMeasureRepeat()) {
    3021          219 :                     return toMeasureRepeat(e);
    3022              :                 }
    3023              :             }
    3024              :         }
    3025           87 :         Measure* nm = m->nextMeasure();
    3026           87 :         if (nm && nm->measureRepeatCount(staffIdx) == m->measureRepeatCount(staffIdx) + 1) {
    3027           87 :             m = nm;
    3028              :         } else {
    3029            0 :             break;
    3030              :         }
    3031              :     }
    3032            0 :     return nullptr;
    3033              : }
    3034              : 
    3035              : //---------------------------------------------------------
    3036              : //   measureRepeatNumMeasures
    3037              : //---------------------------------------------------------
    3038              : 
    3039          776 : int Measure::measureRepeatNumMeasures(staff_idx_t staffIdx) const
    3040              : {
    3041          776 :     MeasureRepeat* el = measureRepeatElement(staffIdx);
    3042          776 :     if (!el) {
    3043          674 :         return 0;
    3044              :     }
    3045          102 :     return el->numMeasures();
    3046              : }
    3047              : 
    3048              : //---------------------------------------------------------
    3049              : //   isOneMeasureRepeat
    3050              : //---------------------------------------------------------
    3051              : 
    3052            0 : bool Measure::isOneMeasureRepeat(staff_idx_t staffIdx) const
    3053              : {
    3054            0 :     return measureRepeatNumMeasures(staffIdx) == 1;
    3055              : }
    3056              : 
    3057              : //---------------------------------------------------------
    3058              : //   nextIsOneMeasureRepeat
    3059              : //---------------------------------------------------------
    3060              : 
    3061            0 : bool Measure::nextIsOneMeasureRepeat(staff_idx_t staffIdx) const
    3062              : {
    3063            0 :     if (!nextMeasure()) {
    3064            0 :         return false;
    3065              :     }
    3066            0 :     return nextMeasure()->isOneMeasureRepeat(staffIdx);
    3067              : }
    3068              : 
    3069              : //---------------------------------------------------------
    3070              : //   prevIsOneMeasureRepeat
    3071              : //---------------------------------------------------------
    3072              : 
    3073            0 : bool Measure::prevIsOneMeasureRepeat(staff_idx_t staffIdx) const
    3074              : {
    3075            0 :     if (!prevMeasure()) {
    3076            0 :         return false;
    3077              :     }
    3078            0 :     return prevMeasure()->isOneMeasureRepeat(staffIdx);
    3079              : }
    3080              : 
    3081       676774 : ChordRest* Measure::lastChordRest(track_idx_t track) const
    3082              : {
    3083      3022830 :     for (const Segment* seg = last(); seg; seg = seg->prev()) {
    3084      2534051 :         if (!seg->isChordRestType()) {
    3085      1102269 :             continue;
    3086              :         }
    3087      1431782 :         ChordRest* cr = seg->cr(track);
    3088      1431782 :         if (!cr) {
    3089      1243787 :             continue;
    3090              :         }
    3091              : 
    3092       187995 :         return cr;
    3093              :     }
    3094       488779 :     return nullptr;
    3095              : }
    3096              : 
    3097       922863 : ChordRest* Measure::firstChordRest(track_idx_t track) const
    3098              : {
    3099      4135581 :     for (const Segment* seg = first(); seg; seg = seg->next()) {
    3100      3453853 :         if (!seg->isChordRestType()) {
    3101      1608655 :             continue;
    3102              :         }
    3103      1845198 :         ChordRest* cr = seg->cr(track);
    3104      1845198 :         if (!cr) {
    3105      1604063 :             continue;
    3106              :         }
    3107              : 
    3108       241135 :         return cr;
    3109              :     }
    3110       681728 :     return nullptr;
    3111              : }
    3112              : 
    3113              : //-------------------------------------------------------------------
    3114              : //   userStretch
    3115              : //-------------------------------------------------------------------
    3116              : 
    3117       183167 : double Measure::userStretch() const
    3118              : {
    3119       183167 :     return score()->layoutOptions().isMode(LayoutMode::FLOAT) ? 1.0 : m_userStretch;
    3120              : }
    3121              : 
    3122              : //---------------------------------------------------------
    3123              : //   nextElementStaff
    3124              : //---------------------------------------------------------
    3125              : 
    3126            0 : EngravingItem* Measure::nextElementStaff(staff_idx_t staff, EngravingItem* fromItem)
    3127              : {
    3128            0 :     EngravingItem* e = fromItem ? fromItem : score()->selection().element();
    3129            0 :     if (!e && !score()->selection().elements().empty()) {
    3130            0 :         e = score()->selection().elements().front();
    3131              :     }
    3132              : 
    3133              :     // handle measure elements
    3134            0 :     if (e->ownershipParent() == this) {
    3135            0 :         auto i = std::find(el().begin(), el().end(), e);
    3136            0 :         if (i != el().end()) {
    3137            0 :             if (++i != el().end()) {
    3138            0 :                 EngravingItem* resElement = *i;
    3139            0 :                 if (resElement) {
    3140            0 :                     return resElement;
    3141              :                 }
    3142              :             }
    3143              :         }
    3144              :     }
    3145              : 
    3146            0 :     for (; e && !e->isSegment(); e = e->layoutParent()) {
    3147              :     }
    3148            0 :     Segment* seg = toSegment(e);
    3149            0 :     Segment* nextSegment = seg ? seg->next() : first();
    3150            0 :     EngravingItem* next = nextSegment->firstElementOfSegment(staff);
    3151            0 :     if (next) {
    3152            0 :         return next;
    3153              :     }
    3154              : 
    3155            0 :     return Navigation::lastElement(score());
    3156              : }
    3157              : 
    3158              : //---------------------------------------------------------
    3159              : //   prevElementStaff
    3160              : //---------------------------------------------------------
    3161              : 
    3162            0 : EngravingItem* Measure::prevElementStaff(staff_idx_t staff, EngravingItem* fromItem)
    3163              : {
    3164            0 :     EngravingItem* e = fromItem ? fromItem : score()->selection().element();
    3165            0 :     if (!e && !score()->selection().elements().empty()) {
    3166            0 :         e = score()->selection().elements().front();
    3167              :     }
    3168              : 
    3169              :     // handle measure elements
    3170            0 :     if (e->ownershipParent() == this) {
    3171            0 :         auto i = std::find(el().rbegin(), el().rend(), e);
    3172            0 :         if (i != el().rend()) {
    3173            0 :             if (++i != el().rend()) {
    3174            0 :                 EngravingItem* resElement = *i;
    3175            0 :                 if (resElement) {
    3176            0 :                     return resElement;
    3177              :                 }
    3178              :             }
    3179              :         }
    3180              :     }
    3181              : 
    3182            0 :     Measure* prevM = prevMeasureMM();
    3183            0 :     if (prevM) {
    3184            0 :         Segment* seg = prevM->last();
    3185            0 :         if (seg) {
    3186            0 :             return seg->lastElementForNavigation(staff);
    3187              :         }
    3188              :     }
    3189            0 :     return Navigation::firstElement(score());
    3190              : }
    3191              : 
    3192          774 : double Measure::firstNoteRestSegmentX(bool leading) const
    3193              : {
    3194          774 :     const System* sys = system();
    3195          774 :     double margin = style().styleAbsolute(Sid::headerToLineStartDistance);
    3196         3029 :     for (const Segment* seg = first(); seg; seg = seg->next()) {
    3197         3029 :         if (seg->isChordRestType()) {
    3198          774 :             double noteRestPos = seg->measure()->pos().x() + seg->pos().x();
    3199          774 :             if (!leading) {
    3200            0 :                 return noteRestPos;
    3201              :             }
    3202              : 
    3203              :             // first CR found; back up to previous segment
    3204          774 :             seg = seg->prevActive();
    3205          977 :             while (seg && (seg->allElementsInvisible() || seg->hasTimeSigAboveStaves())) {
    3206          203 :                 seg = seg->prevActive();
    3207              :             }
    3208          774 :             if (seg) {
    3209              :                 // find maximum width
    3210          734 :                 double width = 0.0;
    3211          734 :                 size_t n = score()->nstaves();
    3212         2050 :                 for (staff_idx_t i = 0; i < n; ++i) {
    3213         1316 :                     if (!sys->staff(i)->show()) {
    3214            0 :                         continue;
    3215              :                     }
    3216         1316 :                     EngravingItem* e = seg->element(i * VOICES);
    3217         1316 :                     if (e && e->addToSkyline()) {
    3218         1304 :                         width = std::max(width, e->pos().x() + e->ldata()->bbox().right());
    3219              :                     }
    3220              :                 }
    3221          734 :                 if (seg->isStartRepeatBarLineType()) {
    3222           59 :                     margin = style().styleAbsolute(Sid::lineEndToBarlineDistance);
    3223              :                 }
    3224          734 :                 return std::min(seg->measure()->pos().x() + seg->pos().x() + width + margin, noteRestPos);
    3225           40 :             } else if (!isFirstInSystem() && !isFirstInSection() && prevMeasure()) {
    3226            3 :                 const BarLine* endBl = prevMeasure()->endBarLine();
    3227            3 :                 const Segment* endBlSeg = endBl ? endBl->segment() : nullptr;
    3228              : 
    3229            3 :                 if (!endBlSeg) {
    3230            0 :                     return noteRestPos;
    3231              :                 }
    3232              : 
    3233            3 :                 double width = 0.0;
    3234            3 :                 if (endBl && endBl->addToSkyline()) {
    3235            3 :                     width = std::max(width, endBl->pos().x() + endBl->ldata()->bbox().right());
    3236              :                 }
    3237              : 
    3238            3 :                 const double startBlMargin = style().styleAbsolute(Sid::barlineToLineStartDistance);
    3239              : 
    3240            3 :                 return std::min(endBlSeg->measure()->pos().x() + endBlSeg->pos().x() + width + startBlMargin, noteRestPos);
    3241              :             } else {
    3242           37 :                 return noteRestPos;
    3243              :             }
    3244              :         }
    3245              :     }
    3246              : 
    3247            0 :     return margin;
    3248              : }
    3249              : 
    3250          657 : double Measure::endingXForOpenEndedLines() const
    3251              : {
    3252          657 :     const System* sys = system();
    3253          657 :     double margin = style().styleAbsolute(Sid::lineEndToBarlineDistance);
    3254          657 :     double systemEndX = sys->ldata()->bbox().width();
    3255              : 
    3256          657 :     Segment* lastSeg = last();
    3257         1667 :     while (lastSeg && !lastSeg->isType(SegmentType::BarLineTypes)) {
    3258         1010 :         lastSeg = lastSeg->prevEnabled();
    3259              :     }
    3260          657 :     if (!lastSeg) {
    3261          247 :         return systemEndX - margin;
    3262              :     }
    3263              : 
    3264          410 :     return lastSeg->x() + x() - margin;
    3265              : }
    3266              : 
    3267              : //---------------------------------------------------------
    3268              : //   accessibleInfo
    3269              : //---------------------------------------------------------
    3270              : 
    3271            0 : String Measure::accessibleInfo() const
    3272              : {
    3273            0 :     return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), String::number(measureNumber() + 1));
    3274              : }
    3275              : 
    3276            0 : void Measure::styleChanged()
    3277              : {
    3278            0 :     if (endBarLineType() == BarLineType::END_REPEAT) {
    3279            0 :         score()->undoUpdatePlayCountText(this);
    3280              :     }
    3281            0 :     MeasureBase::styleChanged();
    3282            0 : }
    3283              : 
    3284              : //---------------------------------------------------
    3285              : //    computeTicks
    3286              : //    set ticks for all segments
    3287              : //       return minTick
    3288              : //---------------------------------------------------
    3289              : 
    3290        30515 : void Measure::computeTicks()
    3291              : {
    3292       124595 :     for (Segment* segment = firstActive(); segment; segment = segment->nextActive()) {
    3293        94080 :         Segment* nextSegment = segment->nextActive();
    3294        94080 :         Fraction nextTick = nextSegment ? nextSegment->rtick() : ticks();
    3295        94080 :         segment->setTicks(nextTick - segment->rtick());
    3296              :     }
    3297              : 
    3298        31014 :     for (Segment* segment = first(SegmentType::TimeTick); segment; segment = segment->next(SegmentType::TimeTick)) {
    3299          499 :         segment->setTicks(Fraction(0, 1));
    3300          499 :         Segment* nextSegment = segment->next();
    3301          708 :         while (nextSegment) {
    3302          337 :             Fraction tickDiff = nextSegment->rtick() - segment->rtick();
    3303          337 :             if (!tickDiff.isZero()) {
    3304          128 :                 segment->setTicks(tickDiff);
    3305          128 :                 break;
    3306              :             }
    3307          209 :             nextSegment = nextSegment->next();
    3308              :         }
    3309          499 :         if (segment->ticks().isZero()) {
    3310          371 :             segment->setTicks(ticks() - segment->rtick());
    3311              :         }
    3312              :     }
    3313        30515 : }
    3314              : 
    3315              : //---------------------------------------------------------
    3316              : //   anacrusisOffset
    3317              : //      determine if measure is anacrusis
    3318              : //      and return tick offset relative to measure end
    3319              : //---------------------------------------------------------
    3320              : 
    3321        74525 : Fraction Measure::anacrusisOffset() const
    3322              : {
    3323        74525 :     return isAnacrusis() ? (timesig() - ticks()) : Fraction(0, 1);
    3324              : }
    3325              : 
    3326              : //---------------------------------------------------------
    3327              : //   endBarLine
    3328              : //      return the first one
    3329              : //---------------------------------------------------------
    3330              : 
    3331        14754 : const BarLine* Measure::endBarLine() const
    3332              : {
    3333        14754 :     return endBarLine(0, true);
    3334              : }
    3335              : 
    3336        14755 : const BarLine* Measure::endBarLine(staff_idx_t staffIdx, bool first) const
    3337              : {
    3338              :     // search barline segment:
    3339        14755 :     Segment* s = last();
    3340        16854 :     while (s && !s->isEndBarLineType()) {
    3341         2099 :         s = s->prev();
    3342              :     }
    3343              : 
    3344        14755 :     if (s) {
    3345        14212 :         for (const EngravingItem* e : s->elist()) {
    3346              :             // Return first barline or barline with matching staffIdx
    3347        14212 :             if (e && (e->staffIdx() == staffIdx || first)) {
    3348        14212 :                 return toBarLine(e);
    3349              :             }
    3350              :         }
    3351              :     }
    3352          543 :     return nullptr;
    3353              : }
    3354              : 
    3355              : //---------------------------------------------------------
    3356              : //   endBarLineType
    3357              : //    Assume all barlines have same type if there is more
    3358              : //    than one.
    3359              : //---------------------------------------------------------
    3360              : 
    3361         4257 : BarLineType Measure::endBarLineType() const
    3362              : {
    3363         4257 :     const BarLine* bl = endBarLine();
    3364         4257 :     return bl ? bl->barLineType() : BarLineType::NORMAL;
    3365              : }
    3366              : 
    3367              : //---------------------------------------------------------
    3368              : //   endBarLineVisible
    3369              : //    Assume all barlines have same visibility if there is more
    3370              : //    than one.
    3371              : //---------------------------------------------------------
    3372              : 
    3373         3207 : bool Measure::endBarLineVisible() const
    3374              : {
    3375         3207 :     const BarLine* bl = endBarLine();
    3376         3207 :     return bl ? bl->visible() : true;
    3377              : }
    3378              : 
    3379          111 : const BarLine* Measure::startBarLine() const
    3380              : {
    3381          111 :     return startBarLine(0, true);
    3382              : }
    3383              : 
    3384          111 : const BarLine* Measure::startBarLine(staff_idx_t staffIdx, bool firstStaff) const
    3385              : {
    3386              :     // search barline segment:
    3387          111 :     Segment* s = first();
    3388          654 :     while (s && !(s->isStartRepeatBarLineType() || s->isBeginBarLineType())) {
    3389          543 :         s = s->next();
    3390              :     }
    3391              :     // search first element
    3392          111 :     if (s) {
    3393           23 :         for (const EngravingItem* e : s->elist()) {
    3394           23 :             if (e && (e->staffIdx() == staffIdx || firstStaff)) {
    3395           23 :                 return toBarLine(e);
    3396              :             }
    3397              :         }
    3398              :     }
    3399           88 :     return nullptr;
    3400              : }
    3401              : 
    3402              : //---------------------------------------------------------
    3403              : //   triggerLayout
    3404              : //---------------------------------------------------------
    3405              : 
    3406         2576 : void Measure::triggerLayout() const
    3407              : {
    3408         2576 :     if (prev() || next()) { // avoid triggering layout before getting added to a score
    3409         1599 :         score()->setLayout(tick(), endTick(), 0, score()->nstaves() - 1, this);
    3410              :     }
    3411         2576 : }
    3412              : 
    3413            0 : void Measure::triggerLayout(staff_idx_t staffIdx) const
    3414              : {
    3415            0 :     score()->setLayout(tick(), endTick(), staffIdx, staffIdx, this);
    3416            0 : }
    3417              : 
    3418              : //---------------------------------------------------------
    3419              : //   setEndBarLineType
    3420              : //     Create a *generated* barline with the given type and
    3421              : //     properties if none exists. Modify if it exists.
    3422              : //     Useful for import filters.
    3423              : //---------------------------------------------------------
    3424              : 
    3425          692 : void Measure::setEndBarLineType(BarLineType val, track_idx_t track, bool visible, Color color)
    3426              : {
    3427          692 :     Segment* seg = undoGetSegment(SegmentType::EndBarLine, endTick());
    3428              :     // get existing bar line for this staff, if any
    3429          692 :     BarLine* bl = toBarLine(seg->element(track));
    3430          692 :     if (!bl) {
    3431              :         // no suitable bar line: create a new one
    3432          678 :         bl = Factory::createBarLine(seg);
    3433          678 :         bl->setTrack(track);
    3434          678 :         Part* part = score()->staff(track / VOICES)->part();
    3435              :         // by default, barlines for multi-staff parts should span across staves
    3436          678 :         if (part && part->nstaves() > 1) {
    3437           16 :             bl->setSpanStaff(true);
    3438              :         }
    3439          678 :         score()->addElement(bl);
    3440              :     }
    3441          692 :     bl->setGenerated(false);
    3442          692 :     bl->setBarLineType(val);
    3443          692 :     bl->setVisible(visible);
    3444          692 :     if (color.isValid()) {
    3445            0 :         bl->setColor(color);
    3446              :     }
    3447          692 : }
    3448              : 
    3449              : //---------------------------------------------------------
    3450              : //   checkHeader
    3451              : //---------------------------------------------------------
    3452              : 
    3453        11648 : void Measure::checkHeader()
    3454              : {
    3455        11950 :     for (Segment* seg = first(); seg; seg = seg->next()) {
    3456        11817 :         if (seg->enabled() && seg->header()) {
    3457        11515 :             setHeader(seg->header());
    3458        11515 :             break;
    3459              :         }
    3460              :     }
    3461        11648 : }
    3462              : 
    3463              : //---------------------------------------------------------
    3464              : //   checkTrailer
    3465              : //---------------------------------------------------------
    3466              : 
    3467        35132 : void Measure::checkTrailer()
    3468              : {
    3469       131290 :     for (Segment* seg = last(); seg != first(); seg = seg->prev()) {
    3470        96836 :         if (seg->enabled() && seg->trailer()) {
    3471          678 :             setTrailer(seg->trailer());
    3472          678 :             break;
    3473              :         }
    3474              :     }
    3475        35132 : }
    3476              : 
    3477        26615 : void Measure::checkEndOfMeasureChange()
    3478              : {
    3479        26615 :     bool found = false;
    3480        78399 :     for (Segment* seg = last(); seg != first(); seg = seg->prev()) {
    3481        51807 :         if (seg->enabled() && seg->endOfMeasureChange()) {
    3482           23 :             setEndOfMeasureChange(seg->endOfMeasureChange());
    3483           23 :             found = true;
    3484           23 :             break;
    3485              :         }
    3486              :     }
    3487              : 
    3488        26615 :     if (!found) {
    3489        26592 :         setEndOfMeasureChange(false);
    3490              :     }
    3491        26615 : }
    3492              : 
    3493            0 : bool Measure::canAddStringTunings(staff_idx_t staffIdx) const
    3494              : {
    3495            0 :     Staff* staff = score()->staff(staffIdx);
    3496            0 :     if (!staff) {
    3497            0 :         return false;
    3498              :     }
    3499              : 
    3500            0 :     if (!staff->isPrimaryStaff()) {
    3501            0 :         staff = staff->primaryStaff();
    3502            0 :         if (!staff) {
    3503            0 :             return false;
    3504              :         }
    3505              : 
    3506            0 :         staffIdx = staff->idx();
    3507              :     }
    3508              : 
    3509            0 :     const StringData* stringData = staff->originPart(tick())->instrument(tick())->stringData();
    3510            0 :     if (!stringData || stringData->frettedStrings() == 0) {
    3511            0 :         return false;
    3512              :     }
    3513              : 
    3514              :     // already a string tunings element in this measure
    3515            0 :     bool alreadyHasStringTunings = false;
    3516            0 :     for (const Segment& segment : m_segments) {
    3517            0 :         for (EngravingItem* element : segment.annotations()) {
    3518            0 :             if (element && element->isStringTunings() && element->staffIdx() == staffIdx) {
    3519            0 :                 alreadyHasStringTunings = true;
    3520            0 :                 break;
    3521              :             }
    3522              :         }
    3523              :     }
    3524              : 
    3525            0 :     return !alreadyHasStringTunings;
    3526              : }
    3527              : 
    3528            0 : bool Measure::canAddStaffTypeChange(staff_idx_t staffIdx) const
    3529              : {
    3530            0 :     if (isMMRest()) {
    3531            0 :         return false;
    3532              :     }
    3533              : 
    3534            0 :     for (const EngravingObject* child : el()) {
    3535            0 :         if (!child || !child->isStaffTypeChange()) {
    3536            0 :             continue;
    3537              :         }
    3538              : 
    3539            0 :         const StaffTypeChange* stc = toStaffTypeChange(child);
    3540            0 :         if (stc->staffIdx() == staffIdx) {
    3541              :             // Staff already has a StaffTypeChange at this measure...
    3542            0 :             return false;
    3543              :         }
    3544              :     }
    3545              : 
    3546            0 :     return true;
    3547              : }
    3548              : 
    3549            0 : Fraction Measure::maxTicks() const
    3550              : {
    3551            0 :     Segment* s = first();
    3552            0 :     Fraction maxticks = Fraction(0, 1);
    3553            0 :     if (isMMRest()) {
    3554            0 :         return timesig();
    3555              :     }
    3556            0 :     while (s) {
    3557            0 :         if (s->enabled() && s->isChordRestType()) {
    3558            0 :             maxticks = std::max(maxticks, s->ticks());
    3559              :         }
    3560            0 :         s = s->next();
    3561              :     }
    3562            0 :     return maxticks;
    3563              : }
    3564              : 
    3565        32917 : void Measure::respaceSegments()
    3566              : {
    3567        32917 :     double x = 0.0;
    3568              :     // Find starting x position (i.e. position of first relevant segment)
    3569        33638 :     for (Segment& s : m_segments) {
    3570        33638 :         if (s.enabled() && s.visible() && !s.allElementsInvisible()) {
    3571        32917 :             x = s.x();
    3572        32917 :             break;
    3573              :         }
    3574              :     }
    3575              :     // Start respacing segments
    3576       150698 :     for (Segment& s : m_segments) {
    3577       117781 :         if (s.isTimeTickType()) {
    3578          292 :             continue;
    3579              :         }
    3580       117489 :         s.mutldata()->setPosX(x);
    3581       117489 :         if (s.enabled() && s.visible() && !s.allElementsInvisible()) {
    3582       110459 :             x += s.width(LD_ACCESS::BAD);
    3583              :         }
    3584              :     }
    3585              :     // Update measure width
    3586        32917 :     setWidth(x);
    3587        32917 : }
    3588              : }
        

Generated by: LCOV version 2.0-1