LCOV - code coverage report
Current view: top level - src/engraving/dom - measurebase.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 68.0 % 572 389
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              : #include "measurebase.h"
      24              : 
      25              : #include "../editing/editpagelocks.h"
      26              : #include "../editing/editsystemlocks.h"
      27              : 
      28              : #include "actionicon.h"
      29              : #include "box.h"
      30              : #include "factory.h"
      31              : #include "layoutbreak.h"
      32              : #include "measure.h"
      33              : #include "page.h"
      34              : #include "score.h"
      35              : #include "staff.h"
      36              : #include "stafftypechange.h"
      37              : #include "system.h"
      38              : 
      39              : #include "log.h"
      40              : 
      41              : using namespace mu;
      42              : using namespace mu::engraving;
      43              : 
      44              : //---------------------------------------------------------
      45              : //   MeasureBase
      46              : //---------------------------------------------------------
      47              : 
      48        18589 : MeasureBase::MeasureBase(const ElementType& type, Score* parent)
      49        18589 :     : EngravingItem(type, parent)
      50              : {
      51        18589 : }
      52              : 
      53            0 : void MeasureBase::setOwnershipParent(Score* score)
      54              : {
      55            0 :     EngravingItem::setOwnershipParent(score);
      56            0 : }
      57              : 
      58            1 : void MeasureBase::setOwnershipParent(Box* box)
      59              : {
      60            1 :     EngravingItem::setOwnershipParent(box);
      61            1 : }
      62              : 
      63       917118 : EngravingItem* MeasureBase::layoutParent() const
      64              : {
      65       917118 :     if (m_system) {
      66       915565 :         return m_system;
      67              :     }
      68              :     // e.g. a horizontal frame nested inside a vertical frame is placed within its parent frame
      69         1553 :     return EngravingItem::layoutParent();
      70              : }
      71              : 
      72            0 : MeasureBase::MeasureBase(const MeasureBase& m)
      73            0 :     : EngravingItem(m)
      74              : {
      75            0 :     m_next     = m.m_next;
      76            0 :     m_prev     = m.m_prev;
      77            0 :     m_tick     = m.m_tick;
      78              : 
      79            0 :     for (EngravingItem* e : m.m_el) {
      80            0 :         add(e->clone());
      81              :     }
      82            0 : }
      83              : 
      84              : //---------------------------------------------------------
      85              : //   clearElements
      86              : //---------------------------------------------------------
      87              : 
      88            0 : void MeasureBase::clearElements()
      89              : {
      90            0 :     muse::DeleteAll(m_el);
      91            0 :     m_el.clear();
      92            0 : }
      93              : 
      94              : //---------------------------------------------------------
      95              : //   takeElements
      96              : //---------------------------------------------------------
      97              : 
      98            0 : ElementList MeasureBase::takeElements()
      99              : {
     100            0 :     ElementList l;
     101            0 :     l.swap(m_el);
     102            0 :     return l;
     103              : }
     104              : 
     105              : //---------------------------------------------------------
     106              : //   setScore
     107              : //---------------------------------------------------------
     108              : 
     109            0 : void MeasureBase::setScore(Score* score)
     110              : {
     111            0 :     EngravingItem::setScore(score);
     112            0 :     for (EngravingItem* e : m_el) {
     113            0 :         e->setScore(score);
     114              :     }
     115            0 : }
     116              : 
     117              : //---------------------------------------------------------
     118              : //   MeasureBase
     119              : //---------------------------------------------------------
     120              : 
     121        17307 : MeasureBase::~MeasureBase()
     122              : {
     123        17307 :     muse::DeleteAll(m_el);
     124        17307 : }
     125              : 
     126            1 : System* MeasureBase::prevNonVBoxSystem() const
     127              : {
     128            1 :     const System* currSystem = system();
     129            1 :     const MeasureBase* firstInCurrSystem = currSystem ? currSystem->first() : nullptr;
     130            1 :     IF_ASSERT_FAILED(firstInCurrSystem) {
     131            0 :         return nullptr;
     132              :     }
     133              : 
     134              :     // TODO: This logic is coupled to moveMeasureToPrevSystem - it should be possible to
     135              :     // move a MeasureBase from below a VBox (or n VBoxes) to above. Once that's achieved,
     136              :     // we can remove lastIsValid and simply iterate until we find a "non VBox system"...
     137            1 :     const MeasureBase* lastInPrevSystem = firstInCurrSystem->prevMM();
     138            1 :     const bool lastIsValid = lastInPrevSystem && !lastInPrevSystem->isVBoxBase();
     139              : 
     140            1 :     return lastIsValid ? lastInPrevSystem->system() : nullptr;
     141              : }
     142              : 
     143            1 : System* MeasureBase::nextNonVBoxSystem() const
     144              : {
     145            1 :     const System* currSystem = system();
     146            1 :     const MeasureBase* lastInCurrSystem = currSystem ? currSystem->last() : nullptr;
     147            1 :     IF_ASSERT_FAILED(lastInCurrSystem) {
     148            0 :         return nullptr;
     149              :     }
     150              : 
     151              :     // TODO: This logic is coupled to moveMeasureToNextSystem - it should be possible to
     152              :     // move a MeasureBase from above a VBox (or n VBoxes) to below. Once that's achieved,
     153              :     // we can remove firstIsValid and simply iterate until we find a "non VBox system"...
     154            1 :     const MeasureBase* firstInNextSystem = lastInCurrSystem->nextMM();
     155            1 :     const bool firstIsValid = firstInNextSystem && !firstInNextSystem->isVBoxBase();
     156              : 
     157            1 :     return firstIsValid ? firstInNextSystem->system() : nullptr;
     158              : }
     159              : 
     160            8 : Page* MeasureBase::page() const
     161              : {
     162            8 :     return system() ? system()->page() : nullptr;
     163              : }
     164              : 
     165            1 : Page* MeasureBase::prevPage() const
     166              : {
     167            1 :     Page* curPage = page();
     168            1 :     IF_ASSERT_FAILED(curPage) {
     169            0 :         return nullptr;
     170              :     }
     171              : 
     172            1 :     Page* prevPage = curPage;
     173            4 :     for (const MeasureBase* mb = this; mb && prevPage == curPage; mb = mb->prevMM()) {
     174            3 :         prevPage = mb->system()->page();
     175              :     }
     176              : 
     177            1 :     return prevPage != curPage ? prevPage : nullptr;
     178              : }
     179              : 
     180            1 : Page* MeasureBase::nextPage() const
     181              : {
     182            1 :     Page* curPage = page();
     183            1 :     IF_ASSERT_FAILED(curPage) {
     184            0 :         return nullptr;
     185              :     }
     186              : 
     187            1 :     Page* nextPage = curPage;
     188            6 :     for (const MeasureBase* mb = this; mb && nextPage == curPage; mb = mb->nextMM()) {
     189            5 :         nextPage = mb->system()->page();
     190              :     }
     191              : 
     192            1 :     return nextPage != curPage ? nextPage : nullptr;
     193              : }
     194              : 
     195            0 : bool MeasureBase::acceptDrop(EditData& data) const
     196              : {
     197            0 :     const EngravingItem* e = data.dropElement;
     198            0 :     if (!e || !system() || !page()) {
     199            0 :         return false;
     200              :     }
     201              : 
     202            0 :     if (e->isLayoutBreak()) {
     203            0 :         return true;
     204              :     }
     205              : 
     206            0 :     if (e->isActionIcon()) {
     207            0 :         switch (toActionIcon(e)->actionType()) {
     208            0 :         case ActionIconType::PAGE_LOCK:
     209              :         {
     210            0 :             LayoutMode layoutMode = score()->layoutMode();
     211            0 :             return layoutMode == LayoutMode::PAGE;
     212              :         }
     213            0 :         case ActionIconType::SYSTEM_LOCK:
     214              :         {
     215            0 :             LayoutMode layoutMode = score()->layoutMode();
     216            0 :             return layoutMode == LayoutMode::PAGE || layoutMode == LayoutMode::SYSTEM;
     217              :         }
     218            0 :         default: break;
     219              :         }
     220              :     }
     221            0 :     return false;
     222              : }
     223              : 
     224            0 : EngravingItem* MeasureBase::drop(Transaction& tx, EditData& data)
     225              : {
     226            0 :     EngravingItem* e = data.dropElement;
     227            0 :     if (!e || !system() || !page()) {
     228            0 :         delete e;
     229            0 :         return nullptr;
     230              :     }
     231            0 :     if (e->isLayoutBreak()) {
     232            0 :         LayoutBreak* b = toLayoutBreak(e);
     233            0 :         MeasureBase* mb = this;
     234            0 :         if (isMeasure()) {
     235            0 :             Measure* m = toMeasure(this);
     236            0 :             if (m->isMMRest()) {
     237            0 :                 mb = m->mmRestLast();
     238              :             }
     239              :         }
     240            0 :         switch (b->layoutBreakType()) {
     241            0 :         case  LayoutBreakType::PAGE:
     242            0 :             if (mb->pageBreak()) {
     243            0 :                 delete b;
     244            0 :                 b = nullptr;
     245              :             } else {
     246            0 :                 mb->setLineBreak(false);
     247              :             }
     248            0 :             break;
     249            0 :         case  LayoutBreakType::LINE:
     250            0 :             if (mb->lineBreak()) {
     251            0 :                 delete b;
     252            0 :                 b = nullptr;
     253              :             } else {
     254            0 :                 mb->setPageBreak(false);
     255              :             }
     256            0 :             break;
     257            0 :         case  LayoutBreakType::SECTION:
     258            0 :             if (mb->sectionBreak()) {
     259            0 :                 delete b;
     260            0 :                 b = nullptr;
     261              :             } else {
     262            0 :                 mb->setLineBreak(false);
     263              :             }
     264            0 :             break;
     265            0 :         case LayoutBreakType::NOBREAK:
     266            0 :             if (mb->noBreak() || mb->isEndOfSystemLock() || mb->isEndOfPageLock()) {
     267            0 :                 delete b;
     268            0 :                 b = nullptr;
     269              :             } else {
     270            0 :                 mb->setLineBreak(false);
     271            0 :                 mb->setPageBreak(false);
     272              :             }
     273            0 :             break;
     274              :         }
     275            0 :         if (b) {
     276            0 :             if (b->layoutBreakType() != LayoutBreakType::NOBREAK) {
     277            0 :                 EditSystemLocks::removeSystemLocksOnAddLayoutBreak(tx, score(), b->layoutBreakType(), this);
     278              :             }
     279            0 :             b->setTrack(0);
     280            0 :             b->setOwnershipParent(mb);
     281            0 :             score()->undoAddElement(b);
     282              :         }
     283            0 :         mb->cleanupLayoutBreaks(true);
     284            0 :         return b;
     285              :     }
     286            0 :     if (e->isActionIcon()) {
     287            0 :         switch (toActionIcon(e)->actionType()) {
     288            0 :         case ActionIconType::SYSTEM_LOCK:
     289            0 :             EditSystemLocks::makeIntoSystem(tx, score(), system()->first(), this);
     290            0 :             break;
     291            0 :         case ActionIconType::PAGE_LOCK:
     292            0 :             EditPageLocks::makeIntoPage(tx, score(), page()->firstMeasureBase(), this);
     293            0 :             break;
     294            0 :         default:
     295            0 :             LOGD("MeasureBase: cannot drop %s here", e->typeName());
     296            0 :             break;
     297              :         }
     298              :     }
     299            0 :     delete e;
     300            0 :     return nullptr;
     301              : }
     302              : 
     303              : //---------------------------------------------------------
     304              : //   add
     305              : ///   Add new EngravingItem \a el to MeasureBase
     306              : //---------------------------------------------------------
     307              : 
     308         3316 : void MeasureBase::add(EngravingItem* e)
     309              : {
     310         3316 :     if (e->ownershipParent() != this) {
     311           53 :         e->setOwnershipParent(this);
     312              :     }
     313              : 
     314         3316 :     if (e->isLayoutBreak()) {
     315          959 :         LayoutBreak* b = toLayoutBreak(e);
     316          959 :         switch (b->layoutBreakType()) {
     317           20 :         case LayoutBreakType::PAGE:
     318           20 :             setPageBreak(true);
     319           20 :             setLineBreak(false);
     320           20 :             setNoBreak(false);
     321           20 :             break;
     322          857 :         case LayoutBreakType::LINE:
     323          857 :             setPageBreak(false);
     324          857 :             setLineBreak(true);
     325          857 :             setSectionBreak(false);
     326          857 :             setNoBreak(false);
     327          857 :             break;
     328           33 :         case LayoutBreakType::SECTION:
     329           33 :             setLineBreak(false);
     330           33 :             setSectionBreak(true);
     331           33 :             setNoBreak(false);
     332           33 :             if (b->startWithMeasureOne()) {
     333           33 :                 triggerLayoutToEnd();
     334              :             }
     335           33 :             break;
     336           49 :         case LayoutBreakType:: NOBREAK:
     337           49 :             setPageBreak(false);
     338           49 :             setLineBreak(false);
     339           49 :             setSectionBreak(false);
     340           49 :             setNoBreak(true);
     341           49 :             break;
     342              :         }
     343          959 :         if (next()) {
     344          158 :             next()->triggerLayout();
     345              :         }
     346              :     }
     347         3316 :     triggerLayout();
     348         3316 :     m_el.push_back(e);
     349         3316 :     e->added();
     350         3316 : }
     351              : 
     352              : //---------------------------------------------------------
     353              : //   remove
     354              : ///   Remove EngravingItem \a el from MeasureBase.
     355              : //---------------------------------------------------------
     356              : 
     357           29 : void MeasureBase::remove(EngravingItem* el)
     358              : {
     359           29 :     if (el->isLayoutBreak()) {
     360           29 :         LayoutBreak* lb = toLayoutBreak(el);
     361           29 :         switch (lb->layoutBreakType()) {
     362            2 :         case LayoutBreakType::PAGE:
     363            2 :             setPageBreak(false);
     364            2 :             break;
     365           17 :         case LayoutBreakType::LINE:
     366           17 :             setLineBreak(false);
     367           17 :             break;
     368            0 :         case LayoutBreakType::SECTION:
     369            0 :             setSectionBreak(false);
     370            0 :             if (lb->startWithMeasureOne()) {
     371            0 :                 triggerLayoutToEnd();
     372              :             }
     373            0 :             break;
     374           10 :         case LayoutBreakType::NOBREAK:
     375           10 :             setNoBreak(false);
     376           10 :             break;
     377              :         }
     378              :     }
     379              : 
     380           29 :     if (!m_el.remove(el)) {
     381            0 :         LOGD("MeasureBase(%p)::remove(%s,%p) not found", this, el->typeName(), el);
     382              :     } else {
     383           29 :         el->removed();
     384              :     }
     385              : 
     386           29 :     triggerLayout();
     387           29 :     if (next()) {
     388           28 :         next()->triggerLayout();
     389              :     }
     390           29 : }
     391              : 
     392              : //---------------------------------------------------------
     393              : //   nextMeasure
     394              : //---------------------------------------------------------
     395              : 
     396       557797 : Measure* MeasureBase::nextMeasure() const
     397              : {
     398       557797 :     MeasureBase* m = m_next;
     399              :     for (;;) {
     400       560714 :         if (m == 0 || m->isMeasure()) {
     401       557797 :             break;
     402              :         }
     403         2917 :         m = m->m_next;
     404              :     }
     405       557797 :     return toMeasure(m);
     406              : }
     407              : 
     408              : //---------------------------------------------------------
     409              : //   nextMeasureMM
     410              : //---------------------------------------------------------
     411              : 
     412       146742 : Measure* MeasureBase::nextMeasureMM() const
     413              : {
     414       146742 :     Measure* mm = nextMeasure();
     415       146742 :     if (mm && style().styleB(Sid::createMultiMeasureRests) && mm->hasMMRest()) {
     416          392 :         return mm->mmRest();
     417              :     }
     418       146350 :     return mm;
     419              : }
     420              : 
     421              : //---------------------------------------------------------
     422              : //   prevMeasure
     423              : //---------------------------------------------------------
     424              : 
     425       695831 : Measure* MeasureBase::prevMeasure() const
     426              : {
     427       695831 :     MeasureBase* m = prev();
     428       778678 :     while (m) {
     429       645995 :         if (m->isMeasure()) {
     430       563148 :             return toMeasure(m);
     431              :         }
     432        82847 :         m = m->prev();
     433              :     }
     434       132683 :     return nullptr;
     435              : }
     436              : 
     437              : //---------------------------------------------------------
     438              : //   prevMeasureMM
     439              : //---------------------------------------------------------
     440              : 
     441       320972 : Measure* MeasureBase::prevMeasureMM() const
     442              : {
     443       320972 :     Measure* m = prevMeasure();
     444       320972 :     if (m) {
     445       273277 :         return m->coveringMMRestOrThis();
     446              :     }
     447              : 
     448        47695 :     return nullptr;
     449              : }
     450              : 
     451         8858 : const MeasureBase* MeasureBase::mbWithPrecedingSectionBreak() const
     452              : {
     453              :     // we're trying to find the MeasureBase that determines
     454              :     // if the next one after this starts a new section
     455              :     // if this is a measure, it's the one that determines this
     456              :     // but if it is a frame, we may need to look backwards
     457         8858 :     const MeasureBase* mb = this;
     458        11701 :     while (mb && !mb->isMeasure() && !mb->sectionBreak()) {
     459         2843 :         mb = mb->prev();
     460              :     }
     461         8858 :     return mb;
     462              : }
     463              : 
     464              : //---------------------------------------------------------
     465              : //   pause
     466              : //---------------------------------------------------------
     467              : 
     468          813 : double MeasureBase::pause() const
     469              : {
     470          813 :     const LayoutBreak* layoutBreak = sectionBreakElement();
     471          813 :     return layoutBreak ? layoutBreak->pause() : 0.0;
     472              : }
     473              : 
     474              : //---------------------------------------------------------
     475              : //   top
     476              : //---------------------------------------------------------
     477              : 
     478     17106640 : MeasureBase* MeasureBase::top() const
     479              : {
     480     17106640 :     const MeasureBase* mb = this;
     481     17106640 :     while (mb->ownershipParent()) {
     482     17106640 :         if (mb->ownershipParent()->isMeasureBase()) {
     483            0 :             mb = toMeasureBase(mb->ownershipParent());
     484              :         } else {
     485     17106640 :             break;
     486              :         }
     487              :     }
     488     17106640 :     return const_cast<MeasureBase*>(mb);
     489              : }
     490              : 
     491              : //---------------------------------------------------------
     492              : //   getInScore
     493              : //---------------------------------------------------------
     494              : 
     495           19 : MeasureBase* MeasureBase::getInScore(Score* score, bool useNextMeasureFallback) const
     496              : {
     497           19 :     MeasureBase* newMB = nullptr;
     498           19 :     if (!isMeasure() && !excludeFromOtherParts()) {
     499            0 :         for (auto e : linkList()) {
     500            0 :             if (e->score() == score) {
     501            0 :                 newMB = toMeasureBase(e);
     502            0 :                 break;
     503              :             }
     504            0 :         }
     505              :     }
     506           19 :     if (isMeasure() || (!newMB && useNextMeasureFallback)) {
     507           19 :         newMB = score->tick2measure(tick());
     508              :     }
     509           19 :     if (!newMB) {
     510            0 :         LOGD("measure base not found in score");
     511              :     }
     512           19 :     return newMB;
     513              : }
     514              : 
     515              : //---------------------------------------------------------
     516              : //   tick
     517              : //---------------------------------------------------------
     518              : 
     519     17096791 : Fraction MeasureBase::tick() const
     520              : {
     521     17096791 :     const MeasureBase* mb = top();
     522     17096791 :     return mb ? mb->m_tick : Fraction(-1, 1);
     523              : }
     524              : 
     525        22192 : void MeasureBase::setTick(const Fraction& f)
     526              : {
     527        22192 :     m_tick = f;
     528        22192 : }
     529              : 
     530              : //---------------------------------------------------------
     531              : //   triggerLayout
     532              : //---------------------------------------------------------
     533              : 
     534         9788 : void MeasureBase::triggerLayout() const
     535              : {
     536              :     // for measurebases within other measurebases (e.g., hbox within vbox), use top level
     537         9788 :     const MeasureBase* mb = top();
     538              :     // avoid triggering layout before getting added to a score
     539         9788 :     if (mb->prev() || mb->next()) {
     540          444 :         score()->setLayout(mb->tick(), muse::nidx, mb);
     541              :     }
     542         9788 : }
     543              : 
     544              : //---------------------------------------------------------
     545              : //   scanElements
     546              : //---------------------------------------------------------
     547              : 
     548         3382 : void MeasureBase::scanElements(std::function<void(EngravingItem*)> func)
     549              : {
     550         3382 :     if (isMeasure()) {
     551         3391 :         for (EngravingItem* e : m_el) {
     552          142 :             staff_idx_t staffIdx = e->staffIdx();
     553          142 :             if (staffIdx != muse::nidx && staffIdx >= score()->staves().size()) {
     554            0 :                 LOGD("MeasureBase::scanElements: bad staffIdx %zu in element %s", staffIdx, e->typeName());
     555              :             }
     556          142 :             if ((e->track() == muse::nidx) || e->systemFlag() || toMeasure(this)->visible(staffIdx)) {
     557          142 :                 e->scanElements(func);
     558              :             }
     559              :         }
     560              :     } else {
     561          377 :         for (EngravingItem* e : m_el) {
     562          244 :             e->scanElements(func);
     563              :         }
     564              :     }
     565         3382 :     if (isBox()) {
     566          133 :         func(this);
     567              :     }
     568         3382 : }
     569              : 
     570              : //---------------------------------------------------------
     571              : //   first
     572              : //---------------------------------------------------------
     573              : 
     574        28510 : MeasureBase* Score::first() const
     575              : {
     576        28510 :     return m_measures.first();
     577              : }
     578              : 
     579              : //---------------------------------------------------------
     580              : //   last
     581              : //---------------------------------------------------------
     582              : 
     583         9421 : MeasureBase* Score::last()  const
     584              : {
     585         9421 :     return m_measures.last();
     586              : }
     587              : 
     588              : //---------------------------------------------------------
     589              : //   undoSetBreak
     590              : //---------------------------------------------------------
     591              : 
     592          504 : void MeasureBase::undoSetBreak(bool v, LayoutBreakType type)
     593              : {
     594          504 :     switch (type) {
     595          142 :     case LayoutBreakType::LINE:
     596          142 :         if (lineBreak() == v) {
     597          142 :             return;
     598              :         }
     599            0 :         setLineBreak(v);
     600            0 :         break;
     601          208 :     case LayoutBreakType::PAGE:
     602          208 :         if (pageBreak() == v) {
     603          208 :             return;
     604              :         }
     605            0 :         if (v && lineBreak()) {
     606            0 :             setLineBreak(false);
     607              :         }
     608            0 :         setPageBreak(v);
     609            0 :         break;
     610          114 :     case LayoutBreakType::SECTION:
     611          114 :         if (sectionBreak() == v) {
     612          114 :             return;
     613              :         }
     614            0 :         if (v && lineBreak()) {
     615            0 :             setLineBreak(false);
     616              :         }
     617            0 :         setSectionBreak(v);
     618            0 :         break;
     619           40 :     case LayoutBreakType::NOBREAK:
     620           40 :         if (noBreak() == v) {
     621           28 :             return;
     622              :         }
     623           12 :         if (v) {
     624            9 :             setLineBreak(false);
     625            9 :             setPageBreak(false);
     626            9 :             setSectionBreak(false);
     627              :         }
     628           12 :         setNoBreak(v);
     629           12 :         break;
     630              :     }
     631              : 
     632           12 :     if (v) {
     633            9 :         MeasureBase* mb = (isMeasure() && toMeasure(this)->isMMRest()) ? toMeasure(this)->mmRestLast() : this;
     634            9 :         LayoutBreak* lb = Factory::createLayoutBreak(mb);
     635            9 :         lb->setLayoutBreakType(type);
     636            9 :         lb->setTrack(0);
     637            9 :         score()->undoAddElement(lb);
     638              :     }
     639           12 :     cleanupLayoutBreaks(true);
     640              : }
     641              : 
     642              : //---------------------------------------------------------
     643              : //   cleanupLayoutBreaks
     644              : //---------------------------------------------------------
     645              : 
     646          726 : void MeasureBase::cleanupLayoutBreaks(bool undo)
     647              : {
     648              :     // remove unneeded layout breaks
     649          726 :     std::vector<EngravingItem*> toDelete;
     650         1474 :     for (EngravingItem* e : el()) {
     651          748 :         if (e->isLayoutBreak()) {
     652          726 :             switch (toLayoutBreak(e)->layoutBreakType()) {
     653          631 :             case LayoutBreakType::LINE:
     654          631 :                 if (!lineBreak()) {
     655            0 :                     toDelete.push_back(e);
     656              :                 }
     657          631 :                 break;
     658           15 :             case LayoutBreakType::PAGE:
     659           15 :                 if (!pageBreak()) {
     660            0 :                     toDelete.push_back(e);
     661              :                 }
     662           15 :                 break;
     663           33 :             case LayoutBreakType::SECTION:
     664           33 :                 if (!sectionBreak()) {
     665            0 :                     toDelete.push_back(e);
     666              :                 }
     667           33 :                 break;
     668           47 :             case LayoutBreakType::NOBREAK:
     669           47 :                 if (!noBreak()) {
     670            3 :                     toDelete.push_back(e);
     671              :                 }
     672           47 :                 break;
     673              :             }
     674              :         }
     675              :     }
     676          729 :     for (EngravingItem* e : toDelete) {
     677            3 :         if (undo) {
     678            3 :             score()->undoRemoveElement(e);
     679              :         } else {
     680            0 :             m_el.remove(e);
     681              :         }
     682              :     }
     683          726 : }
     684              : 
     685              : //---------------------------------------------------------
     686              : //   nextMM
     687              : //---------------------------------------------------------
     688              : 
     689        83974 : MeasureBase* MeasureBase::nextMM() const
     690              : {
     691       167948 :     if (m_next
     692        72405 :         && m_next->isMeasure()
     693        71829 :         && style().styleB(Sid::createMultiMeasureRests)
     694       156379 :         && toMeasure(m_next)->hasMMRest()) {
     695          306 :         return toMeasure(m_next)->mmRest();
     696              :     }
     697        83668 :     return m_next;
     698              : }
     699              : 
     700              : //---------------------------------------------------------
     701              : //   prevMM
     702              : //---------------------------------------------------------
     703              : 
     704         6692 : MeasureBase* MeasureBase::prevMM() const
     705              : {
     706        13384 :     if (m_prev
     707         6692 :         && m_prev->isMeasure()
     708        13384 :         && style().styleB(Sid::createMultiMeasureRests)) {
     709          114 :         return const_cast<Measure*>(toMeasure(m_prev)->coveringMMRestOrThis());
     710              :     }
     711         6578 :     return m_prev;
     712              : }
     713              : 
     714              : //---------------------------------------------------------
     715              : //   index
     716              : //---------------------------------------------------------
     717              : 
     718        10051 : int MeasureBase::index() const
     719              : {
     720        10051 :     int idx = 0;
     721        10051 :     MeasureBase* m = score()->first();
     722        10051 :     Measure* mmRestFirst = nullptr;
     723        10051 :     if (isMeasure() && toMeasure(this)->isMMRest()) {
     724            0 :         mmRestFirst = toMeasure(this)->mmRestFirst();
     725              :     }
     726       186907 :     while (m) {
     727       186907 :         if (m == this || m == mmRestFirst) {
     728        10051 :             return idx;
     729              :         }
     730       176856 :         m = m->next();
     731       176856 :         ++idx;
     732              :     }
     733            0 :     return -1;
     734              : }
     735              : 
     736              : //---------------------------------------------------------
     737              : //   measureIndex
     738              : //    returns index of measure counting only Measures but
     739              : //    skipping other MeasureBase descendants
     740              : //---------------------------------------------------------
     741              : 
     742           28 : int MeasureBase::measureIndex() const
     743              : {
     744           28 :     int idx = 0;
     745           28 :     MeasureBase* m = score()->firstMeasure();
     746           28 :     Measure* mmRestFirst = nullptr;
     747           28 :     if (isMeasure() && toMeasure(this)->isMMRest()) {
     748            0 :         mmRestFirst = toMeasure(this)->mmRestFirst();
     749              :     }
     750          109 :     while (m) {
     751          109 :         if (m == this || m == mmRestFirst) {
     752           28 :             return idx;
     753              :         }
     754           81 :         m = m->next();
     755           81 :         if (m && m->isMeasure()) {
     756           81 :             ++idx;
     757              :         }
     758              :     }
     759            0 :     return -1;
     760              : }
     761              : 
     762            0 : bool MeasureBase::isBefore(const EngravingItem* other) const
     763              : {
     764            0 :     if (other->isMeasureBase()) {
     765            0 :         const MeasureBase* otherMb = toMeasureBase(other);
     766            0 :         return isBefore(otherMb);
     767              :     }
     768              : 
     769            0 :     return EngravingItem::isBefore(other);
     770              : }
     771              : 
     772        13704 : bool MeasureBase::isBefore(const MeasureBase* other) const
     773              : {
     774        13704 :     if (this == other) {
     775         2313 :         return false;
     776              :     }
     777              : 
     778        11391 :     Fraction otherTick = other->tick();
     779        11391 :     if (otherTick != m_tick) {
     780        11258 :         return m_tick < otherTick;
     781              :     }
     782              : 
     783          133 :     if (this->isMeasure() && other->isMeasure()) {
     784              :         // (this == other) has already been excluded, so this is only
     785              :         // possible if one is the overlying mmRest starting on the other.
     786              :         // Let's set by convention that the mmRest isBefore the underlying measure.
     787            1 :         return toMeasure(this)->isMMRest();
     788              :     }
     789              : 
     790          132 :     bool otherIsMMRest = other->isMeasure() && toMeasure(other)->isMMRest();
     791          182 :     for (const MeasureBase* mb = otherIsMMRest ? nextMM() : next(); mb && mb->tick() == m_tick;
     792           25 :          mb = otherIsMMRest ? mb->nextMM() : mb->next()) {
     793          141 :         if (mb == other) {
     794          116 :             return true;
     795              :         }
     796              :     }
     797              : 
     798           16 :     return false;
     799              : }
     800              : 
     801        39099 : const RangeLock* MeasureBase::systemLock() const
     802              : {
     803        39099 :     return score()->systemLocks()->lockContaining(this);
     804              : }
     805              : 
     806        25073 : bool MeasureBase::isStartOfSystemLock() const
     807              : {
     808        25073 :     const RangeLock* lock = score()->systemLocks()->lockStartingAt(this);
     809        25073 :     return lock != nullptr;
     810              : }
     811              : 
     812        28872 : bool MeasureBase::isEndOfSystemLock() const
     813              : {
     814        28872 :     const RangeLock* lock = systemLock();
     815        28872 :     return lock && lock->endMB() == this;
     816              : }
     817              : 
     818        49197 : const RangeLock* MeasureBase::pageLock() const
     819              : {
     820        49197 :     return score()->pageLocks()->lockContaining(this);
     821              : }
     822              : 
     823        31260 : bool MeasureBase::isStartOfPageLock() const
     824              : {
     825        31260 :     const RangeLock* lock = score()->pageLocks()->lockStartingAt(this);
     826        31260 :     return lock != nullptr;
     827              : }
     828              : 
     829        38985 : bool MeasureBase::isEndOfPageLock() const
     830              : {
     831        38985 :     const RangeLock* lock = pageLock();
     832        38985 :     return lock && lock->endMB() == this;
     833              : }
     834              : 
     835              : //---------------------------------------------------------
     836              : //   sectionBreakElement
     837              : //---------------------------------------------------------
     838              : 
     839       203447 : LayoutBreak* MeasureBase::sectionBreakElement() const
     840              : {
     841       203447 :     if (sectionBreak()) {
     842          519 :         for (EngravingItem* e : el()) {
     843          519 :             if (e->isLayoutBreak() && toLayoutBreak(e)->isSectionBreak()) {
     844          497 :                 return toLayoutBreak(e);
     845              :             }
     846              :         }
     847              :     }
     848              : 
     849       202950 :     return nullptr;
     850              : }
     851              : 
     852              : //---------------------------------------------------------
     853              : //   MeasureBaseList
     854              : //---------------------------------------------------------
     855              : 
     856         2334 : MeasureBaseList::MeasureBaseList()
     857              : {
     858         2334 :     m_first = nullptr;
     859         2334 :     m_last  = nullptr;
     860         2334 :     m_size  = 0;
     861         2334 : }
     862              : 
     863            0 : void MeasureBaseList::clear()
     864              : {
     865            0 :     m_first = nullptr;
     866            0 :     m_last = nullptr;
     867            0 :     m_size = 0;
     868            0 :     m_tickIndex.clear();
     869            0 : }
     870              : 
     871              : //---------------------------------------------------------
     872              : //   push_back
     873              : //---------------------------------------------------------
     874              : 
     875        18047 : void MeasureBaseList::push_back(MeasureBase* m)
     876              : {
     877        18047 :     ++m_size;
     878        18047 :     if (m_last) {
     879        15838 :         m_last->setNext(m);
     880        15838 :         m->setPrev(m_last);
     881        15838 :         m->setNext(0);
     882              :     } else {
     883         2209 :         m_first = m;
     884         2209 :         m->setPrev(0);
     885         2209 :         m->setNext(0);
     886              :     }
     887        18047 :     m_last = m;
     888        18047 : }
     889              : 
     890              : //---------------------------------------------------------
     891              : //   push_front
     892              : //---------------------------------------------------------
     893              : 
     894           18 : void MeasureBaseList::push_front(MeasureBase* m)
     895              : {
     896           18 :     ++m_size;
     897           18 :     if (m_first) {
     898           18 :         m_first->setPrev(m);
     899           18 :         m->setNext(m_first);
     900           18 :         m->setPrev(0);
     901              :     } else {
     902            0 :         m_last = m;
     903            0 :         m->setPrev(0);
     904            0 :         m->setNext(0);
     905              :     }
     906           18 :     m_first = m;
     907           18 : }
     908              : 
     909              : //---------------------------------------------------------
     910              : //   add
     911              : //    insert m before m->next()
     912              : //---------------------------------------------------------
     913              : 
     914          249 : void MeasureBaseList::add(MeasureBase* m)
     915              : {
     916          249 :     MeasureBase* el = m->next();
     917          249 :     if (el == 0) {
     918          231 :         append(m);
     919          231 :         return;
     920              :     }
     921           18 :     if (el == m_first) {
     922           18 :         push_front(m);
     923           18 :         return;
     924              :     }
     925            0 :     ++m_size;
     926            0 :     m->setPrev(el->prev());
     927            0 :     el->prev()->setNext(m);
     928            0 :     el->setPrev(m);
     929              : }
     930              : 
     931              : //---------------------------------------------------------
     932              : //   remove
     933              : //---------------------------------------------------------
     934              : 
     935            4 : void MeasureBaseList::remove(MeasureBase* m)
     936              : {
     937            4 :     --m_size;
     938            4 :     if (m->prev()) {
     939            1 :         m->prev()->setNext(m->next());
     940              :     } else {
     941            3 :         m_first = m->next();
     942              :     }
     943            4 :     if (m->next()) {
     944            4 :         m->next()->setPrev(m->prev());
     945              :     } else {
     946            0 :         m_last = m->prev();
     947              :     }
     948            4 : }
     949              : 
     950              : //---------------------------------------------------------
     951              : //   insert
     952              : //---------------------------------------------------------
     953              : 
     954          382 : void MeasureBaseList::insert(MeasureBase* fm, MeasureBase* lm)
     955              : {
     956          447 :     for (MeasureBase* m = fm; m != lm; m = m->next()) {
     957           65 :         ++m_size;
     958              :     }
     959          382 :     ++m_size;
     960          382 :     MeasureBase* pm = fm->prev();
     961          382 :     if (pm) {
     962          325 :         pm->setNext(fm);
     963              :     } else {
     964           57 :         m_first = fm;
     965              :     }
     966          382 :     MeasureBase* nm = lm->next();
     967          382 :     if (nm) {
     968          136 :         nm->setPrev(lm);
     969              :     } else {
     970          246 :         m_last = lm;
     971              :     }
     972          382 : }
     973              : 
     974              : //---------------------------------------------------------
     975              : //   remove
     976              : //---------------------------------------------------------
     977              : 
     978           80 : void MeasureBaseList::remove(MeasureBase* fm, MeasureBase* lm)
     979              : {
     980          139 :     for (MeasureBase* m = fm; m != lm; m = m->next()) {
     981           59 :         --m_size;
     982              :     }
     983           80 :     --m_size;
     984           80 :     MeasureBase* pm = fm->prev();
     985           80 :     MeasureBase* nm = lm->next();
     986           80 :     if (pm) {
     987           61 :         pm->setNext(nm);
     988              :     } else {
     989           19 :         m_first = nm;
     990              :     }
     991           80 :     if (nm) {
     992           52 :         nm->setPrev(pm);
     993              :     } else {
     994           28 :         m_last = pm;
     995              :     }
     996           80 : }
     997              : 
     998              : //---------------------------------------------------------
     999              : //   change
    1000              : //---------------------------------------------------------
    1001              : 
    1002            0 : void MeasureBaseList::change(MeasureBase* ob, MeasureBase* nb)
    1003              : {
    1004            0 :     nb->setPrev(ob->prev());
    1005            0 :     nb->setNext(ob->next());
    1006            0 :     if (ob->prev()) {
    1007            0 :         ob->prev()->setNext(nb);
    1008              :     }
    1009            0 :     if (ob->next()) {
    1010            0 :         ob->next()->setPrev(nb);
    1011              :     }
    1012            0 :     if (ob == m_last) {
    1013            0 :         m_last = nb;
    1014              :     }
    1015            0 :     if (ob == m_first) {
    1016            0 :         m_first = nb;
    1017              :     }
    1018            0 :     if (nb->isBox()) {
    1019            0 :         nb->setSystem(ob->system());
    1020              :     }
    1021            0 :     for (EngravingItem* e : nb->el()) {
    1022            0 :         e->setOwnershipParent(nb);
    1023              :     }
    1024            0 : }
    1025              : 
    1026              : //---------------------------------------------------------
    1027              : //   append
    1028              : //    append measure to the end of the list and update
    1029              : //    tick index
    1030              : //---------------------------------------------------------
    1031              : 
    1032        18047 : void MeasureBaseList::append(MeasureBase* m)
    1033              : {
    1034        18047 :     assert(!m->next());
    1035        18047 :     assert(!m->prev() || m->prev() == m_last);
    1036              : 
    1037        18047 :     push_back(m);
    1038        18047 :     m_tickIndex.emplace(std::make_pair(m->tick().ticks(), m));
    1039        18047 : }
    1040              : 
    1041       129979 : Measure* MeasureBaseList::measureByTick(int tick) const
    1042              : {
    1043       129979 :     if (empty() || tick > m_last->endTick().ticks()) {
    1044          888 :         return nullptr;
    1045              :     }
    1046              : 
    1047       129091 :     auto it = m_tickIndex.upper_bound(tick);
    1048              : 
    1049       129091 :     if (it == m_tickIndex.begin()) {
    1050            1 :         MeasureBase* mb = it->second;
    1051              : 
    1052            1 :         if (mb->isMeasure()) {
    1053            0 :             return toMeasure(mb);
    1054              :         }
    1055            1 :         return nullptr;
    1056              :     }
    1057              : 
    1058       129090 :     --it;
    1059            0 :     for (;; --it) {
    1060       129090 :         if (it == m_tickIndex.begin()) {
    1061        18677 :             MeasureBase* mb = it->second;
    1062              : 
    1063        18677 :             if (mb->isMeasure()) {
    1064        18649 :                 return toMeasure(mb);
    1065              :             }
    1066           28 :             return nullptr;
    1067              :         }
    1068              : 
    1069       110413 :         MeasureBase* mb = it->second;
    1070       110413 :         if (!mb) {
    1071            0 :             break;
    1072              :         }
    1073              : 
    1074       110413 :         if (mb->isMeasure()) {
    1075       110413 :             return toMeasure(mb);
    1076              :         }
    1077            0 :     }
    1078              : 
    1079            0 :     return nullptr;
    1080              : }
    1081              : 
    1082           10 : MeasureBase* MeasureBaseList::firstMeasureBaseAtTick(int tick) const
    1083              : {
    1084           10 :     if (empty() || tick > m_last->endTick().ticks()) {
    1085            0 :         return nullptr;
    1086              :     }
    1087              : 
    1088           10 :     auto it = m_tickIndex.upper_bound(tick);
    1089              : 
    1090           10 :     if (it != m_tickIndex.begin()) {
    1091           10 :         --it;
    1092              :     }
    1093           10 :     return it->second;
    1094              : }
    1095              : 
    1096            0 : std::vector<MeasureBase*> MeasureBaseList::measureBasesAtTick(int tick) const
    1097              : {
    1098            0 :     std::vector<MeasureBase*> result;
    1099            0 :     if (empty() || tick > m_last->endTick().ticks()) {
    1100            0 :         return result;
    1101              :     }
    1102              : 
    1103            0 :     result = muse::values(m_tickIndex, tick);
    1104              : 
    1105            0 :     return result;
    1106            0 : }
    1107              : 
    1108         2340 : void MeasureBaseList::updateTickIndex()
    1109              : {
    1110         2340 :     m_tickIndex.clear();
    1111              : 
    1112        21426 :     for (MeasureBase* mb = m_first; mb; mb = mb->next()) {
    1113        19086 :         m_tickIndex.emplace(std::make_pair(mb->tick().ticks(), mb));
    1114              :     }
    1115         2340 : }
        

Generated by: LCOV version 2.0-1