LCOV - code coverage report
Current view: top level - src/engraving/rendering/score - segmentlayout.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 87.4 % 111 97
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 "segmentlayout.h"
      23              : 
      24              : #include "dom/part.h"
      25              : #include "dom/drumset.h"
      26              : #include "dom/parenthesis.h"
      27              : #include "dom/staff.h"
      28              : 
      29              : #include "tlayout.h"
      30              : #include "chordlayout.h"
      31              : #include "horizontalspacing.h"
      32              : 
      33              : using namespace mu::engraving::rendering::score;
      34              : 
      35       134513 : void SegmentLayout::layoutMeasureIndependentElements(const Segment& segment, track_idx_t track, const LayoutContext& ctx)
      36              : {
      37              :     LAYOUT_CALL() << segment.typeName() << "(" << segment.eid() << ")";
      38              : 
      39       134513 :     if (segment.isJustType(SegmentType::KeySig)) {
      40         6699 :         KeySig* ks = toKeySig(segment.element(track));
      41         6699 :         if (ks) {
      42         6443 :             TLayout::layoutKeySig(ks, ks->mutldata(), ctx.conf());         // LD_INDEPENDENT
      43              :         }
      44       127814 :     } else if (segment.isJustType(SegmentType::Clef)) {
      45          378 :         Clef* cl = item_cast<Clef*>(segment.element(track));
      46          378 :         if (cl) {
      47          286 :             cl->setSmall(true);
      48          286 :             TLayout::layoutClef(cl, cl->mutldata(), ctx.conf());         // LD_INDEPENDENT
      49              :         }
      50       127436 :     } else if (segment.isType(SegmentType::HeaderClef)) {
      51         6270 :         Clef* cl = item_cast<Clef*>(segment.element(track));
      52         6270 :         if (cl) {
      53         6101 :             TLayout::layoutClef(cl, cl->mutldata(), ctx.conf());         // LD_INDEPENDENT
      54              :         }
      55       121166 :     } else if (segment.isType(SegmentType::TimeSig)) {
      56         6189 :         TimeSig* ts = item_cast<TimeSig*>(segment.element(track));
      57         6189 :         if (ts) {
      58         6043 :             TLayout::layoutTimeSig(ts, ts->mutldata(), ctx);         // LD_INDEPENDENT
      59              :         }
      60       114977 :     } else if (segment.isType(SegmentType::Ambitus)) {
      61            2 :         Ambitus* am = item_cast<Ambitus*>(segment.element(track));
      62            2 :         if (am) {
      63            2 :             TLayout::layoutAmbitus(am, am->mutldata(), ctx);         // LD_INDEPENDENT
      64              :         }
      65       114975 :     } else if (segment.isType(SegmentType::BarLine)) {
      66           24 :         BarLine* bl = toBarLine(segment.element(track));
      67           24 :         if (bl) {
      68              :             // check conditions (see TLayout::layoutBarLine)
      69              :             {
      70           24 :                 for (const EngravingItem* e : *bl->el()) {
      71            0 :                     if (e->isType(ElementType::ARTICULATION)) {
      72            0 :                         LD_CONDITION(item_cast<const Articulation*>(e)->ldata()->symId.has_value());
      73              :                     }
      74              :                 }
      75              :             }
      76           24 :             TLayout::layoutBarLine(bl, bl->mutldata(), ctx);
      77              :         }
      78              :     }
      79       134513 : }
      80              : 
      81        87846 : void SegmentLayout::setChordMag(const Staff* staff, const Segment& segment, track_idx_t startTrack, track_idx_t endTrack,
      82              :                                 const LayoutConfiguration& conf)
      83              : {
      84              :     LAYOUT_CALL() << LAYOUT_ITEM_INFO(staff) << " " << segment.typeName() << "(" << segment.eid() << ")";
      85              : 
      86        87846 :     IF_ASSERT_FAILED(segment.isJustType(SegmentType::ChordRest)) {
      87            0 :         return;
      88              :     }
      89              : 
      90        87846 :     const double staffMag = staff->staffMag(&segment);
      91        87846 :     const double smallNoteMag = conf.styleD(Sid::smallNoteMag);
      92        87846 :     const double graceNoteMag = conf.styleD(Sid::graceNoteMag);
      93              : 
      94       439230 :     for (track_idx_t t = startTrack; t < endTrack; ++t) {
      95       351384 :         ChordRest* cr = segment.cr(t);
      96       351384 :         if (!cr) {
      97       264283 :             continue;
      98              :         }
      99              : 
     100        87101 :         double m = staffMag;
     101        87101 :         if (cr->isSmall()) {
     102          308 :             m *= smallNoteMag;
     103              :         }
     104              : 
     105        87101 :         if (cr->isChord()) {
     106        48116 :             double graceMag = m * graceNoteMag;
     107        48116 :             Chord* chord = toChord(cr);
     108        49021 :             for (Chord* c : chord->graceNotes()) {
     109          905 :                 c->mutldata()->setMag(graceMag);
     110              :             }
     111              :         }
     112        87101 :         cr->mutldata()->setMag(m);
     113              :     }
     114              : }
     115              : 
     116            0 : void SegmentLayout::checkStaffMoveValidity(const Segment& segment, track_idx_t startTrack, track_idx_t endTrack)
     117              : {
     118              :     LAYOUT_CALL() << segment.typeName() << "(" << segment.eid() << ")";
     119              : 
     120            0 :     IF_ASSERT_FAILED(segment.isJustType(SegmentType::ChordRest)) {
     121            0 :         return;
     122              :     }
     123              : 
     124            0 :     for (track_idx_t t = startTrack; t < endTrack; ++t) {
     125            0 :         ChordRest* cr = toChordRest(segment.element(t));
     126            0 :         if (cr) {
     127              :             // Check if requested cross-staff is possible
     128            0 :             if (cr->staffMove() || cr->storedStaffMove()) {
     129            0 :                 cr->checkStaffMoveValidity();
     130              :             }
     131              :         }
     132              :     }
     133              : }
     134              : 
     135        87846 : void SegmentLayout::layoutChordDrumset(const Staff* staff, const Segment& segment, track_idx_t startTrack, track_idx_t endTrack,
     136              :                                        const LayoutConfiguration& conf)
     137              : {
     138              :     LAYOUT_CALL() << LAYOUT_ITEM_INFO(staff) << " " << segment.typeName() << "(" << segment.eid() << ")";
     139              : 
     140        87846 :     IF_ASSERT_FAILED(segment.isJustType(SegmentType::ChordRest)) {
     141        85853 :         return;
     142              :     }
     143              : 
     144        87846 :     const Instrument* ins = staff->originPart(segment.tick())->instrument(segment.tick());
     145        87846 :     if (!ins->useDrumset()) {
     146        85853 :         return;
     147              :     }
     148              : 
     149         1993 :     const Drumset* drumset = ins->drumset();
     150         1993 :     IF_ASSERT_FAILED(drumset) {
     151            0 :         return;
     152              :     }
     153              : 
     154         1993 :     const StaffType* st = staff->staffTypeForElement(&segment);
     155              : 
     156         1128 :     auto layoutDrumset = [](Chord* c, const Drumset* drumset, const StaffType* st, double spatium)
     157              :     {
     158         2305 :         for (Note* note : c->notes()) {
     159         1177 :             int pitch = note->pitch();
     160         1177 :             if (!drumset->isValid(pitch)) {
     161              :                 // LOGD("unmapped drum note %d", pitch);
     162         1101 :             } else if (!note->fixed()) {
     163         1078 :                 note->undoChangeProperty(Pid::HEAD_GROUP, drumset->noteHead(pitch));
     164         1078 :                 int line = drumset->line(pitch);
     165         1078 :                 note->setLine(line);
     166              : 
     167         1078 :                 int off  = st->stepOffset();
     168         1078 :                 double ld = st->lineDistance().val();
     169         1078 :                 note->mutldata()->setPosY((line + off * 2.0) * spatium * .5 * ld);
     170              :             }
     171              :         }
     172         1128 :     };
     173              : 
     174         1993 :     double spatium = conf.spatium();
     175         9965 :     for (track_idx_t t = startTrack; t < endTrack; ++t) {
     176         7972 :         Chord* chord = item_cast<Chord*>(segment.element(t), CastMode::MAYBE_BAD); // maybe Rest
     177         7972 :         if (!chord) {
     178         6856 :             continue;
     179              :         }
     180              : 
     181         1128 :         for (Chord* c : chord->graceNotes()) {
     182           12 :             layoutDrumset(c, drumset, st, spatium);
     183              :         }
     184              : 
     185         1116 :         layoutDrumset(chord, drumset, st, spatium);
     186              :     }
     187              : }
     188              : 
     189        87846 : void SegmentLayout::computeChordsUp(const Segment& segment, track_idx_t startTrack, track_idx_t endTrack, const LayoutContext& ctx)
     190              : {
     191        87846 :     IF_ASSERT_FAILED(segment.isJustType(SegmentType::ChordRest)) {
     192            0 :         return;
     193              :     }
     194              : 
     195       439230 :     for (track_idx_t t = startTrack; t < endTrack; ++t) {
     196       351384 :         ChordRest* cr = segment.cr(t);
     197       351384 :         if (!cr) {
     198       264283 :             continue;
     199              :         }
     200              : 
     201        87101 :         if (cr->isChord()) {
     202        48116 :             Chord* chord = toChord(cr);
     203              : 
     204        49021 :             for (Chord* c : chord->graceNotes()) {
     205          905 :                 ChordLayout::computeUp(c, ctx);
     206              :             }
     207              : 
     208        48116 :             ChordLayout::computeUp(chord, ctx);
     209              :         }
     210              :     }
     211              : }
     212              : 
     213        87846 : void SegmentLayout::layoutChordsStem(const Segment& segment, track_idx_t startTrack, track_idx_t endTrack, const LayoutContext& ctx)
     214              : {
     215        87846 :     IF_ASSERT_FAILED(segment.isJustType(SegmentType::ChordRest)) {
     216            0 :         return;
     217              :     }
     218              : 
     219       439230 :     for (track_idx_t t = startTrack; t < endTrack; ++t) {
     220       351384 :         ChordRest* cr = segment.cr(t);
     221       351384 :         if (!cr) {
     222       264283 :             continue;
     223              :         }
     224              : 
     225        87101 :         if (cr->isChord()) {
     226        48116 :             Chord* chord = toChord(cr);
     227              : 
     228        49021 :             for (Chord* c : chord->graceNotes()) {
     229          905 :                 ChordLayout::layoutStem(c, ctx);
     230              :             }
     231              : 
     232        48116 :             ChordLayout::layoutStem(chord, ctx);
     233              :             // stem direction can change later during beam processing
     234              :         }
     235              :     }
     236              : }
        

Generated by: LCOV version 2.0-1