LCOV - code coverage report
Current view: top level - src/engraving/editing - editspanner.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 21.7 % 83 18
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) 2025 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 "editspanner.h"
      24              : 
      25              : #include "../dom/chord.h"
      26              : #include "../dom/engravingitem.h"
      27              : #include "../dom/measure.h"
      28              : #include "../dom/note.h"
      29              : #include "../dom/score.h"
      30              : #include "../dom/segment.h"
      31              : #include "../dom/spanner.h"
      32              : #include "../dom/textlinebase.h"
      33              : #include "../dom/tie.h"
      34              : 
      35              : using namespace mu::engraving;
      36              : 
      37              : //---------------------------------------------------------
      38              : //   EditSpanner
      39              : //---------------------------------------------------------
      40              : 
      41            0 : void EditSpanner::addSpanner(Transaction&, Score* score, Spanner* spanner, const PointF& pos, bool systemStavesOnly)
      42              : {
      43            0 :     staff_idx_t staffIdx = spanner->staffIdx();
      44              :     Segment* segment;
      45            0 :     Measure* measure = score->pos2measure(pos, &staffIdx, /*pitch*/ 0, &segment, /*offset*/ 0);
      46            0 :     if (systemStavesOnly) {
      47            0 :         staffIdx = 0;
      48              :     }
      49              :     // ignore if we do not have a measure
      50            0 :     if (!measure) {
      51            0 :         LOGD("addSpanner: cannot put object here");
      52            0 :         delete spanner;
      53            0 :         return;
      54              :     }
      55              : 
      56              :     // all spanners live in voice 0 (except slurs/ties)
      57            0 :     track_idx_t track = staffIdx == muse::nidx ? muse::nidx : staffIdx * VOICES;
      58              : 
      59            0 :     spanner->setTrack(track);
      60            0 :     spanner->setTrack2(track);
      61              : 
      62            0 :     if (spanner->anchor() == Spanner::Anchor::SEGMENT) {
      63            0 :         spanner->setTick(segment->tick());
      64            0 :         Fraction tick2 = std::min(segment->measure()->endTick(), score->lastMeasure()->endTick());
      65            0 :         spanner->setTick2(tick2);
      66              :     } else { // Anchor::MEASURE, Anchor::CHORD, Anchor::NOTE
      67            0 :         spanner->setTick(measure->tick());
      68            0 :         spanner->setTick2(measure->endTick());
      69              :     }
      70            0 :     spanner->eraseSpannerSegments();
      71              : 
      72            0 :     bool ctrlModifier = isSystemTextLine(spanner) && !systemStavesOnly;
      73            0 :     score->undoAddElement(spanner, true /*addToLinkedStaves*/, ctrlModifier);
      74              : }
      75              : 
      76            0 : void EditSpanner::addSpanner(Transaction&, Score* score, Spanner* spanner, staff_idx_t staffIdx, Segment* startSegment,
      77              :                              Segment* endSegment, bool ctrlModifier)
      78              : {
      79            0 :     track_idx_t track = staffIdx * VOICES;
      80            0 :     spanner->setTrack(track);
      81            0 :     spanner->setTrack2(track);
      82            0 :     for (auto ss : spanner->spannerSegments()) {
      83            0 :         ss->setTrack(track);
      84              :     }
      85              : 
      86            0 :     bool isMeasureAnchor = spanner->anchor() == Spanner::Anchor::MEASURE;
      87            0 :     Fraction tick1 = isMeasureAnchor ? startSegment->measure()->tick() : startSegment->tick();
      88            0 :     spanner->setTick(tick1);
      89              : 
      90            0 :     Fraction tick2;
      91            0 :     if (!endSegment) {
      92            0 :         tick2 = score->lastSegment()->tick();
      93            0 :     } else if (endSegment == startSegment) {
      94            0 :         tick2 = startSegment->measure()->last()->tick();
      95              :     } else {
      96            0 :         tick2 = endSegment->tick();
      97              :     }
      98            0 :     if (isMeasureAnchor) {
      99            0 :         Measure* endMeasure = score->tick2measureMM(tick2);
     100            0 :         if (endMeasure->tick() != tick2) {
     101            0 :             tick2 = endMeasure->endTick();
     102              :         }
     103              :     }
     104              : 
     105            0 :     spanner->setTick2(tick2);
     106            0 :     score->undoAddElement(spanner, true, ctrlModifier);
     107            0 : }
     108              : 
     109              : //---------------------------------------------------------
     110              : //   ChangeSpannerElements
     111              : //---------------------------------------------------------
     112              : 
     113          102 : void ChangeSpannerElements::flip()
     114              : {
     115          102 :     EngravingItem* oldStartElement   = spanner->startElement();
     116          102 :     EngravingItem* oldEndElement     = spanner->endElement();
     117          102 :     bool isPartialSpanner = spanner->isPartialTie() || spanner->isLaissezVib();
     118          102 :     if (spanner->anchor() == Spanner::Anchor::NOTE) {
     119              :         // be sure new spanner elements are of the right type
     120            0 :         if (!isPartialSpanner && (!startElement || !startElement->isNote() || !endElement || !endElement->isNote())) {
     121            0 :             return;
     122              :         }
     123            0 :         Note* oldStartNote = toNote(oldStartElement);
     124            0 :         Note* oldEndNote = toNote(oldEndElement);
     125            0 :         Note* newStartNote = toNote(startElement);
     126            0 :         Note* newEndNote = toNote(endElement);
     127              :         // update spanner's start and end notes
     128            0 :         if ((newStartNote && newEndNote) || (isPartialSpanner && (newStartNote || newEndNote))) {
     129            0 :             spanner->setNoteSpan(newStartNote, newEndNote);
     130            0 :             if (spanner->isTie()) {
     131            0 :                 Tie* tie = toTie(spanner);
     132            0 :                 if (oldStartNote && newStartNote) {
     133            0 :                     oldStartNote->setTieFor(nullptr);
     134            0 :                     newStartNote->setTieFor(tie);
     135              :                 }
     136            0 :                 if (oldEndNote && newEndNote) {
     137            0 :                     oldEndNote->setTieBack(nullptr);
     138            0 :                     newEndNote->setTieBack(tie);
     139              :                 }
     140              :             } else {
     141            0 :                 oldStartNote->removeSpannerFor(spanner);
     142            0 :                 oldEndNote->removeSpannerBack(spanner);
     143            0 :                 newStartNote->addSpannerFor(spanner);
     144            0 :                 newEndNote->addSpannerBack(spanner);
     145            0 :                 if (spanner->isGlissando()) {
     146            0 :                     oldEndNote->chord()->updateEndsNoteAnchoredLine();
     147              :                 }
     148              :             }
     149              :         }
     150              :     } else {
     151          102 :         spanner->setStartElement(startElement);
     152          102 :         spanner->setEndElement(endElement);
     153              :     }
     154          102 :     startElement = oldStartElement;
     155          102 :     endElement   = oldEndElement;
     156          102 :     spanner->triggerLayout();
     157              : }
     158              : 
     159              : //---------------------------------------------------------
     160              : //   ChangeStartEndSpanner
     161              : //---------------------------------------------------------
     162              : 
     163           16 : void ChangeStartEndSpanner::flip()
     164              : {
     165           16 :     EngravingItem* s = spanner->startElement();
     166           16 :     EngravingItem* e = spanner->endElement();
     167           16 :     spanner->setStartElement(start);
     168           16 :     spanner->setEndElement(end);
     169           16 :     start = s;
     170           16 :     end   = e;
     171           16 : }
        

Generated by: LCOV version 2.0-1