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

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2023 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "scoreverticalviewlayout.h"
      23              : 
      24              : #include "containers.h"
      25              : 
      26              : #include "dom/score.h"
      27              : #include "dom/system.h"
      28              : #include "dom/bracket.h"
      29              : #include "dom/layoutbreak.h"
      30              : #include "dom/page.h"
      31              : 
      32              : #include "passresetlayoutdata.h"
      33              : #include "passlayoutindependentitems.h"
      34              : 
      35              : #include "measurelayout.h"
      36              : #include "systemlayout.h"
      37              : #include "pagelayout.h"
      38              : 
      39              : #include "log.h"
      40              : 
      41              : using namespace mu::engraving;
      42              : using namespace mu::engraving::rendering::score;
      43              : 
      44            0 : void ScoreVerticalViewLayout::layoutVerticalView(Score* score, LayoutContext& ctx, const Fraction& stick, const Fraction& etick)
      45              : {
      46            0 :     ctx.mutState().setEndTick(etick);
      47              : 
      48              :     //---------------------------------------------------
      49              :     //    initialize layout context lc
      50              :     //---------------------------------------------------
      51              : 
      52            0 :     MeasureBase* m = score->tick2measure(stick);
      53            0 :     if (m == 0) {
      54            0 :         m = score->first();
      55              :     }
      56              :     // start layout one measure earlier to handle clefs and cautionary elements
      57            0 :     if (m->prevMeasureMM()) {
      58            0 :         m = m->prevMeasureMM();
      59            0 :     } else if (m->prev()) {
      60            0 :         m = m->prev();
      61              :     }
      62            0 :     while (!m->isMeasure() && m->prev()) {
      63            0 :         m = m->prev();
      64              :     }
      65              : 
      66              :     // if the first measure of the score is part of a multi measure rest
      67              :     // m->system() will return a nullptr. We need to find the multi measure
      68              :     // rest which replaces the measure range
      69              : 
      70            0 :     if (!m->system() && m->isMeasure() && toMeasure(m)->hasMMRest()) {
      71            0 :         LOGD("  don’t start with mmrest");
      72            0 :         m = toMeasure(m)->mmRest();
      73              :     }
      74              : 
      75            0 :     if (!ctx.state().isLayoutAll() && m->system()) {
      76            0 :         System* system = m->system();
      77            0 :         system_idx_t systemIndex = muse::indexOf(score->systems(), system);
      78            0 :         ctx.mutState().setPage(system->page());
      79            0 :         ctx.mutState().setPageIdx(score->pageIdx(ctx.state().page()));
      80            0 :         if (ctx.state().pageIdx() == muse::nidx) {
      81            0 :             ctx.mutState().setPageIdx(0);
      82              :         }
      83            0 :         ctx.mutState().setCurSystem(system);
      84            0 :         ctx.mutState().setSystemList(muse::mid(score->systems(), systemIndex));
      85              : 
      86            0 :         if (systemIndex == 0) {
      87            0 :             ctx.mutState().setNextMeasure(ctx.conf().isShowVBox() ? score->first() : score->firstMeasure());
      88              :         } else {
      89            0 :             System* prevSystem = score->systems()[systemIndex - 1];
      90            0 :             ctx.mutState().setNextMeasure(prevSystem->measures().back()->next());
      91              :         }
      92              : 
      93            0 :         score->systems().erase(score->systems().begin() + systemIndex, score->systems().end());
      94            0 :         if (!ctx.state().nextMeasure()->prevMeasure()) {
      95            0 :             ctx.mutState().setMeasureNumber(0);
      96            0 :             ctx.mutState().setTick(Fraction(0, 1));
      97              :         } else {
      98            0 :             const MeasureBase* mb = ctx.state().nextMeasure()->prev();
      99            0 :             if (mb) {
     100            0 :                 mb = mb->mbWithPrecedingSectionBreak();
     101              :             }
     102              : 
     103            0 :             const LayoutBreak* layoutBreak = mb->sectionBreakElement();
     104              :             // TODO: also use mb in else clause here?
     105              :             // probably not, only actual measures have meaningful numbers
     106            0 :             if (layoutBreak && layoutBreak->startWithMeasureOne()) {
     107            0 :                 ctx.mutState().setMeasureNumber(0);
     108              :             } else {
     109            0 :                 ctx.mutState().setMeasureNumber(ctx.state().nextMeasure()->prevMeasure()->measureNumber()                      // will be adjusted later with respect
     110            0 :                                                 + (ctx.state().nextMeasure()->prevMeasure()->excludeFromNumbering() ? 0 : 1)); // to the user-defined offset.
     111              :             }
     112            0 :             ctx.mutState().setTick(ctx.state().nextMeasure()->tick());
     113              :         }
     114              :     } else {
     115            0 :         for (System* s : score->systems()) {
     116            0 :             for (Bracket* b : s->brackets()) {
     117            0 :                 if (b->selected()) {
     118            0 :                     bool selected = b->selected();
     119            0 :                     score->selection().remove(b);
     120            0 :                     BracketItem* item = b->bracketItem();
     121            0 :                     item->setSelected(selected);
     122            0 :                     score->setSelectionChanged(true);
     123              :                 }
     124              :             }
     125              :             // no need to clear the page placement: the systems are deleted below,
     126              :             // and ~System unlinks itself from its page
     127              :         }
     128            0 :         for (MeasureBase* mb = score->first(); mb; mb = mb->next()) {
     129            0 :             mb->setSystem(nullptr);
     130            0 :             if (mb->isMeasure() && toMeasure(mb)->mmRest()) {
     131            0 :                 toMeasure(mb)->mmRest()->setSystem(nullptr);
     132              :             }
     133              :         }
     134            0 :         muse::DeleteAll(score->systems());
     135            0 :         score->systems().clear();
     136              : 
     137            0 :         muse::DeleteAll(score->pages());
     138            0 :         score->pages().clear();
     139              : 
     140            0 :         ctx.mutState().setNextMeasure(ctx.conf().isShowVBox() ? score->first() : score->firstMeasure());
     141              :     }
     142              : 
     143            0 :     ctx.mutState().setPrevMeasure(nullptr);
     144              : 
     145            0 :     PassResetLayoutData resetPass;
     146            0 :     resetPass.run(score, ctx);
     147              : 
     148            0 :     MeasureLayout::getNextMeasure(ctx);
     149            0 :     ctx.mutState().setCurSystem(SystemLayout::collectSystem(ctx));
     150              : 
     151            0 :     if (ctx.state().isLayoutAll()) {
     152            0 :         PassLayoutIndependentItems independentPass;
     153            0 :         independentPass.run(score, ctx);
     154            0 :     }
     155              : 
     156            0 :     doLayout(ctx);
     157            0 : }
     158              : 
     159            0 : void ScoreVerticalViewLayout::doLayout(LayoutContext& ctx)
     160              : {
     161            0 :     const MeasureBase* lmb = nullptr;
     162              :     do {
     163            0 :         PageLayout::getNextPage(ctx);
     164            0 :         PageLayout::collectPage(ctx);
     165              : 
     166            0 :         if (ctx.state().page() && !ctx.state().page()->systems().empty()) {
     167            0 :             lmb = ctx.state().page()->systems().back()->measures().back();
     168              :         } else {
     169            0 :             lmb = nullptr;
     170              :         }
     171              : 
     172              :         // we can stop collecting pages when:
     173              :         // 1) we reach the end of score (curSystem is nullptr)
     174              :         // or
     175              :         // 2) we have fully processed the range and reached a point of stability:
     176              :         //    a) we have completed layout for the range (rangeDone is true)
     177              :         //    b) we haven't collected a system that will need to go on the next page
     178              :         //    c) this page ends with the same measure as the previous layout
     179              :         //    pageOldMeasure will be last measure from previous layout if range was completed on or before this page
     180              :         //    it will be nullptr if this page was never laid out or if we collected a system for next page
     181            0 :     } while (ctx.state().curSystem() && !(ctx.state().rangeDone() && lmb == ctx.state().pageOldMeasure()));
     182              :     // && page->system(0)->measures().back()->tick() > endTick // FIXME: perhaps the first measure was meant? Or last system?
     183              : 
     184            0 :     SystemLayout::centerPendingSystems(ctx);
     185              : 
     186            0 :     if (!ctx.state().curSystem()) {
     187              :         // The end of the score. The remaining systems are not needed...
     188            0 :         muse::DeleteAll(ctx.mutState().systemList());
     189            0 :         ctx.mutState().systemList().clear();
     190              :         // ...and the remaining pages too
     191            0 :         while (ctx.dom().npages() > ctx.state().pageIdx()) {
     192            0 :             Page* p = ctx.mutDom().pages().back();
     193            0 :             ctx.mutDom().pages().pop_back();
     194            0 :             delete p;
     195              :         }
     196              :     } else {
     197            0 :         Page* p = ctx.mutState().curSystem()->page();
     198            0 :         if (p && (p != ctx.state().page())) {
     199            0 :             p->invalidateBspTree();
     200              :         }
     201              :     }
     202            0 :     ctx.mutDom().systems().insert(ctx.mutDom().systems().end(), ctx.state().systemList().begin(), ctx.state().systemList().end());
     203            0 : }
        

Generated by: LCOV version 2.0-1