LCOV - code coverage report
Current view: top level - src/engraving/rendering/score - measurenumberlayout.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 50.9 % 116 59
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              : 
      23              : #include "measurenumberlayout.h"
      24              : #include "measurelayout.h"
      25              : #include "tlayout.h"
      26              : #include "textlayout.h"
      27              : 
      28              : #include "dom/measure.h"
      29              : #include "dom/score.h"
      30              : #include "dom/segment.h"
      31              : #include "dom/staff.h"
      32              : #include "dom/system.h"
      33              : 
      34              : using namespace mu::engraving;
      35              : using namespace mu::engraving::rendering::score;
      36              : 
      37         3851 : void MeasureNumberLayout::layoutMeasureNumber(MeasureNumber* item, MeasureNumber::LayoutData* ldata, const LayoutContext& ctx)
      38              : {
      39         3851 :     MeasureNumberPlacement placementMode = ctx.conf().styleV(Sid::measureNumberPlacementMode).value<MeasureNumberPlacement>();
      40         3851 :     if (placementMode != MeasureNumberPlacement::ON_ALL_STAVES) {
      41         3851 :         item->setPlacement(PlacementV::ABOVE);
      42              :     }
      43              : 
      44         3851 :     layoutMeasureNumberBase(item, ldata);
      45              : 
      46         3851 :     const RectF& itemBBox = ldata->bbox();
      47              : 
      48         3851 :     bool alignToBarline = ctx.conf().styleB(Sid::measureNumberAlignToBarline);
      49         3851 :     AlignH hPlacement = ctx.conf().styleV(Sid::measureNumberHPlacement).value<AlignH>();
      50         3851 :     const Segment* barlineSeg = refBarlineSegment(item, alignToBarline, hPlacement);
      51         3851 :     const BarLine* refBarline = barlineSeg ? toBarLine(barlineSeg->element(item->track())) : nullptr;
      52              : 
      53         3851 :     const Measure* measure = item->measure();
      54              : 
      55         3851 :     if (alignToBarline) {
      56         3851 :         if (refBarline) {
      57         1525 :             double xRef = refBarline->pageX() - measure->pageX();
      58         1525 :             xRef += (hPlacement == AlignH::RIGHT ? 1.0 : hPlacement == AlignH::HCENTER ? 0.5 : 0.0) * refBarline->width();
      59         1525 :             ldata->setPosX(xRef);
      60              :         } else {
      61         2326 :             ldata->setPosX(0.0);
      62              :         }
      63              :     } else {
      64            0 :         Segment* firstCRSeg = measure->first(SegmentType::ChordRest);
      65              :         MeasureLayout::MeasureStartEndPos measureStartEndPos
      66            0 :             = MeasureLayout::getMeasureStartEndPos(measure, firstCRSeg, item->staffIdx(), false, false, ctx);
      67              : 
      68            0 :         if (hPlacement == AlignH::LEFT) {
      69            0 :             if (measure->header()) {
      70            0 :                 ldata->setPosX(measure->firstNoteRestSegmentX(true) - measure->systemPos().x());
      71              :             } else {
      72            0 :                 double xRef = refBarline ? refBarline->pageX() - measure->pageX() : 0.0;
      73            0 :                 ldata->setPosX(xRef);
      74              :             }
      75            0 :         } else if (hPlacement == AlignH::HCENTER) {
      76            0 :             ldata->setPosX(0.5 * (measureStartEndPos.x1 + measureStartEndPos.x2));
      77              :         } else {
      78            0 :             if (refBarline) {
      79            0 :                 double xRef = refBarline->pageX() - measure->pageX() + refBarline->width();
      80            0 :                 ldata->setPosX(xRef);
      81              :             } else {
      82            0 :                 ldata->setPosX(measureStartEndPos.x2);
      83              :             }
      84              :         }
      85              :     }
      86              : 
      87         3851 :     if (hPlacement == AlignH::LEFT) {
      88         2327 :         ldata->moveX(-itemBBox.left());
      89         1524 :     } else if (hPlacement == AlignH::HCENTER) {
      90         1524 :         ldata->moveX(-0.5 * (itemBBox.right() + itemBBox.left()));
      91              :     } else {
      92            0 :         ldata->moveX(-itemBBox.right());
      93              :     }
      94              : 
      95         3851 :     Staff* staff = item->staff();
      96         3851 :     PointF defaultPos = item->defaultPos() * (staff ? staff->staffMag(item->tick()) : 1.0);
      97              : 
      98         3851 :     ldata->move(defaultPos);
      99              : 
     100         3851 :     checkBarlineCollisions(item, barlineSeg, hPlacement, ldata);
     101         3851 : }
     102              : 
     103            0 : void MeasureNumberLayout::layoutMMRestRange(MMRestRange* item, MMRestRange::LayoutData* ldata, const LayoutContext& ctx)
     104              : {
     105            0 :     layoutMeasureNumberBase(item, ldata);
     106              : 
     107            0 :     const Measure* measure = item->measure();
     108            0 :     const Segment* crSeg = measure->first(SegmentType::ChordRest);
     109              :     const MeasureLayout::MeasureStartEndPos measureStartEnd
     110            0 :         = MeasureLayout::getMeasureStartEndPos(measure, crSeg, item->staffIdx(), true, false, ctx);
     111              : 
     112            0 :     const RectF& itemBBox = ldata->bbox();
     113            0 :     AlignH hPlacement = ctx.conf().styleV(Sid::mmRestRangeHPlacement).value<AlignH>();
     114            0 :     if (hPlacement == AlignH::HCENTER) {
     115            0 :         const double x1 = measureStartEnd.x1;
     116            0 :         const double x2 = measureStartEnd.x2;
     117            0 :         ldata->setPosX(0.5 * (x1 + x2) - 0.5 * (itemBBox.right() + itemBBox.left()));
     118            0 :     } else if (hPlacement == AlignH::RIGHT) {
     119            0 :         ldata->setPosX(item->measure()->ldata()->bbox().width() - itemBBox.right());
     120              :     } else {
     121            0 :         ldata->setPosX(measureStartEnd.x1 - itemBBox.left());
     122              :     }
     123              : 
     124            0 :     Staff* staff = item->staff();
     125            0 :     PointF defaultPos = item->defaultPos() * (staff ? staff->staffMag(item->tick()) : 1.0);
     126              : 
     127            0 :     ldata->move(defaultPos);
     128            0 : }
     129              : 
     130         3851 : void MeasureNumberLayout::layoutMeasureNumberBase(MeasureNumberBase* item, MeasureNumberBase::LayoutData* ldata)
     131              : {
     132         3851 :     ldata->setPos(PointF());
     133              : 
     134         3851 :     TextLayout::layoutBaseTextBase1(item, ldata);
     135              : 
     136         3851 :     staff_idx_t effectiveStaffIdx = item->effectiveStaffIdx();
     137         3851 :     Staff* staff = item->score()->staff(effectiveStaffIdx);
     138              : 
     139         3851 :     if (item->placeBelow()) {
     140            0 :         double yoff = ldata->bbox().height();
     141              : 
     142              :         // If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
     143            0 :         if (staff && staff->lines(item->tick()) == 1) {
     144            0 :             yoff += 2.0 * item->spatium();
     145              :         } else {
     146            0 :             yoff += item->staff() ? item->staff()->staffHeight() : 0.0;
     147              :         }
     148              : 
     149            0 :         ldata->setPosY(yoff);
     150              :     } else {
     151         3851 :         double yoff = 0.0;
     152              : 
     153              :         // If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
     154         3851 :         if (staff && staff->lines(item->tick()) == 1) {
     155            3 :             yoff -= 2.0 * item->spatium();
     156              :         }
     157              : 
     158         3851 :         ldata->setPosY(yoff);
     159              :     }
     160         3851 : }
     161              : 
     162         3851 : const Segment* MeasureNumberLayout::refBarlineSegment(const MeasureNumber* item, bool alignToBarline, AlignH hPlacement)
     163              : {
     164         3851 :     Segment* barlineSeg = nullptr;
     165         3851 :     Measure* measure = item->measure();
     166         3851 :     if (alignToBarline || hPlacement == AlignH::LEFT) {
     167         6559 :         for (Segment* seg = measure->first(); seg && seg->tick() == measure->tick() && seg->system() == measure->system();
     168         2708 :              seg = seg->prev1MMenabled()) {
     169         4233 :             if (seg->isType(SegmentType::BarLineTypes) && seg->isActive()) {
     170         1525 :                 barlineSeg = seg;
     171         1525 :                 break;
     172              :             }
     173              :         }
     174         3851 :     } else {
     175            0 :         for (Segment* seg = measure->first(SegmentType::ChordRest);
     176            0 :              seg && seg->tick() <= measure->endTick() && seg->system() == measure->system(); seg = seg->next1enabled()) {
     177            0 :             if (seg->isType(SegmentType::BarLineTypes) && seg->isActive()) {
     178            0 :                 barlineSeg = seg;
     179            0 :                 break;
     180              :             }
     181              :         }
     182              :     }
     183              : 
     184         3851 :     return barlineSeg;
     185              : }
     186              : 
     187         3851 : void MeasureNumberLayout::checkBarlineCollisions(const MeasureNumber* item, const Segment* barlineSeg, AlignH hPlacement,
     188              :                                                  MeasureNumber::LayoutData* ldata)
     189              : {
     190         3851 :     if (hPlacement == AlignH::HCENTER || !item->autoplace()) {
     191         1524 :         return;
     192              :     }
     193              : 
     194         2327 :     const RectF& itemBBox = ldata->bbox();
     195         2327 :     staff_idx_t staffIdx = item->staffIdx();
     196         2327 :     staff_idx_t barlineStaff = muse::nidx;
     197         2327 :     System* system = item->measure()->system();
     198         2327 :     if (item->getProperty(Pid::PLACEMENT).value<PlacementV>() == PlacementV::ABOVE) {
     199         2327 :         barlineStaff = system->prevVisibleStaff(staffIdx);
     200              :     } else {
     201            0 :         barlineStaff = staffIdx;
     202              :     }
     203         2327 :     if (barlineStaff == muse::nidx) {
     204         2327 :         return;
     205              :     }
     206              : 
     207            0 :     const double minBarLineDistance = 0.25 * item->spatium();
     208            0 :     if (!barlineSeg || (barlineSeg->segmentType() != SegmentType::BeginBarLine && !item->score()->staff(barlineStaff)->barLineSpan())) {
     209            0 :         return;
     210              :     }
     211              : 
     212            0 :     BarLine* barline = toBarLine(barlineSeg->element(staff2track(barlineStaff)));
     213            0 :     if (!barline) {
     214            0 :         return;
     215              :     }
     216              : 
     217            0 :     double xCur = item->pageX();
     218            0 :     if (hPlacement == AlignH::LEFT) {
     219            0 :         double xMin = barline->pageX() + barline->width() - itemBBox.left() + minBarLineDistance;
     220            0 :         if (xMin > xCur) {
     221            0 :             ldata->moveX(xMin - xCur);
     222              :         }
     223              :     } else {
     224            0 :         double xMax = barline->pageX() - itemBBox.right() - minBarLineDistance;
     225            0 :         if (xMax < xCur) {
     226            0 :             ldata->moveX(xMax - xCur);
     227              :         }
     228              :     }
     229              : }
        

Generated by: LCOV version 2.0-1