LCOV - code coverage report
Current view: top level - src/engraving/editing - edithairpin.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 119 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) 2026 MuseScore Limited
       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 "edithairpin.h"
      24              : 
      25              : #include "../dom/anchors.h"
      26              : #include "../dom/chord.h"
      27              : #include "../dom/chordrest.h"
      28              : #include "../dom/dynamic.h"
      29              : #include "../dom/factory.h"
      30              : #include "../dom/hairpin.h"
      31              : #include "../dom/measure.h"
      32              : #include "../dom/score.h"
      33              : #include "../dom/segment.h"
      34              : #include "../dom/select.h"
      35              : 
      36              : using namespace mu::engraving;
      37              : 
      38            0 : std::vector<Hairpin*> EditHairpin::addHairpins(Transaction& tx, Score* score, HairpinType type)
      39              : {
      40            0 :     std::vector<Hairpin*> hairpins;
      41              : 
      42              :     // add hairpin on each staff if possible
      43            0 :     const Selection& selection = score->selection();
      44            0 :     if (selection.isRange() && selection.staffStart() != selection.staffEnd() - 1) {
      45            0 :         for (staff_idx_t staffIdx = selection.staffStart(); staffIdx < selection.staffEnd(); ++staffIdx) {
      46            0 :             ChordRest* cr1 = selection.firstChordRest(staffIdx * VOICES);
      47            0 :             ChordRest* cr2 = selection.lastChordRest(staffIdx * VOICES);
      48            0 :             Hairpin* h = cr1 ? addHairpin(tx, score, type, cr1, cr2)
      49            0 :                          : addHairpin(tx, score, type, selection.tickStart(), selection.tickEnd(), staff2track(staffIdx));
      50            0 :             if (h) {
      51            0 :                 hairpins.push_back(h);
      52              :             }
      53              :         }
      54              :     } else {
      55              :         // for single staff range selection, or single selection,
      56              :         // find start & end elements elements
      57            0 :         ChordRest* cr1 = nullptr;
      58            0 :         ChordRest* cr2 = nullptr;
      59            0 :         score->getSelectedStartEndChordRests(cr1, cr2);
      60            0 :         Hairpin* h = addHairpin(tx, score, type, cr1, cr2);
      61            0 :         if (h) {
      62            0 :             hairpins.push_back(h);
      63              :         }
      64              :     }
      65              : 
      66            0 :     for (Hairpin* hairpin : hairpins) {
      67            0 :         hairpin->setInitialTrackAndVoiceAssignment(hairpin->track(), /*curVoiceOnlyOverride*/ false);
      68              :     }
      69              : 
      70            0 :     return hairpins;
      71            0 : }
      72              : 
      73            0 : Hairpin* EditHairpin::addHairpin(Transaction& tx, Score* score, HairpinType type, ChordRest* cr1, ChordRest* cr2)
      74              : {
      75            0 :     if (!cr1) {
      76            0 :         return nullptr;
      77              :     }
      78              : 
      79            0 :     Hairpin* hairpin = Factory::createHairpin(score->dummy());
      80            0 :     hairpin->setHairpinType(type);
      81            0 :     if (type == HairpinType::CRESC_LINE) {
      82            0 :         hairpin->setBeginText(u"cresc.");
      83            0 :         hairpin->setContinueText(u"(cresc.)");
      84            0 :     } else if (type == HairpinType::DIM_LINE) {
      85            0 :         hairpin->setBeginText(u"dim.");
      86            0 :         hairpin->setContinueText(u"(dim.)");
      87              :     }
      88              : 
      89            0 :     addHairpin(tx, score, hairpin, cr1, cr2);
      90              : 
      91            0 :     return hairpin;
      92              : }
      93              : 
      94            0 : Hairpin* EditHairpin::addHairpin(Transaction&, Score* score, HairpinType type, Fraction sTick, Fraction eTick, track_idx_t track)
      95              : {
      96            0 :     Hairpin* hairpin = Factory::createHairpin(score->dummy());
      97            0 :     hairpin->setHairpinType(type);
      98            0 :     if (type == HairpinType::CRESC_LINE) {
      99            0 :         hairpin->setBeginText(u"cresc.");
     100            0 :         hairpin->setContinueText(u"(cresc.)");
     101            0 :     } else if (type == HairpinType::DIM_LINE) {
     102            0 :         hairpin->setBeginText(u"dim.");
     103            0 :         hairpin->setContinueText(u"(dim.)");
     104              :     }
     105              : 
     106            0 :     hairpin->setTrack(track);
     107            0 :     hairpin->setTick(sTick);
     108            0 :     hairpin->setTick2(eTick);
     109              : 
     110            0 :     score->undoAddElement(hairpin);
     111              : 
     112            0 :     return hairpin;
     113              : }
     114              : 
     115            0 : void EditHairpin::addHairpin(Transaction&, Score* score, Hairpin* hairpin, ChordRest* cr1, ChordRest* cr2)
     116              : {
     117            0 :     track_idx_t track = cr1->track();
     118            0 :     Fraction startTick = cr1->tick();
     119              : 
     120            0 :     Fraction endTick = startTick;
     121            0 :     if (score->selection().isRange()) {
     122            0 :         endTick = score->selection().tickEnd();
     123              :     } else {
     124            0 :         if (cr2 && cr2 != cr1) {
     125            0 :             endTick = cr2->endTick();
     126              :         } else {
     127            0 :             endTick = cr1->isChord() ? toChord(cr1)->endTickIncludingTied() : cr1->endTick();
     128              :         }
     129            0 :         const Segment* startSegment = cr2 ? cr2->segment() : cr1->segment();
     130            0 :         for (const Segment* segment = startSegment; segment && segment->tick() < endTick;
     131            0 :              segment = segment->next1(SegmentType::Duration)) {
     132            0 :             if (segment == startSegment) {
     133            0 :                 continue;
     134              :             }
     135            0 :             if (segment->findAnnotation(ElementType::DYNAMIC, track, track)) {
     136            0 :                 endTick = segment->tick();
     137            0 :                 break;
     138              :             }
     139              :         }
     140              :     }
     141              : 
     142            0 :     hairpin->setTrack(track);
     143            0 :     hairpin->setTrack2(track);
     144            0 :     hairpin->setTick(startTick);
     145            0 :     hairpin->setTick2(endTick);
     146              : 
     147            0 :     score->undoAddElement(hairpin);
     148            0 : }
     149              : 
     150            0 : void EditHairpin::addHairpinToDynamic(Transaction&, Score* score, Hairpin* hairpin, Dynamic* dynamic)
     151              : {
     152            0 :     track_idx_t track = dynamic->track();
     153            0 :     hairpin->setTrack(track);
     154            0 :     hairpin->setTrack2(track);
     155              : 
     156            0 :     hairpin->setTick(dynamic->tick());
     157              : 
     158            0 :     Segment* dynamicSegment = dynamic->segment();
     159              : 
     160            0 :     Chord* startChord = nullptr;
     161            0 :     for (Segment* segment = dynamicSegment; segment; segment = segment->prev(SegmentType::ChordRest)) {
     162            0 :         EngravingItem* element = segment->element(track);
     163            0 :         if (element && element->isChord()) {
     164            0 :             startChord = toChord(element);
     165            0 :             break;
     166              :         }
     167              :     }
     168              : 
     169            0 :     Fraction endTick = startChord ? startChord->endTickIncludingTied() : dynamic->segment()->measure()->endTick();
     170              : 
     171            0 :     for (Segment* segment = dynamicSegment; segment && segment->tick() < endTick;
     172            0 :          segment = segment->next1(SegmentType::Duration)) {
     173            0 :         if (segment == dynamicSegment) {
     174            0 :             continue;
     175              :         }
     176            0 :         if (segment->findAnnotation(ElementType::DYNAMIC, track, track)) {
     177            0 :             endTick = segment->tick();
     178            0 :             break;
     179              :         }
     180              :     }
     181              : 
     182            0 :     hairpin->setTick2(endTick);
     183              : 
     184            0 :     hairpin->setVoiceAssignment(dynamic->voiceAssignment());
     185              : 
     186            0 :     score->undoAddElement(hairpin);
     187            0 : }
     188              : 
     189            0 : Hairpin* EditHairpin::addHairpinToDynamicOnGripDrag(Transaction&, Score* score, Dynamic* dynamic, bool isLeftGrip,
     190              :                                                     const muse::PointF& pos)
     191              : {
     192            0 :     const track_idx_t track = dynamic->track();
     193            0 :     staff_idx_t staffIndex = dynamic->staffIdx();
     194            0 :     Segment* seg = nullptr;
     195            0 :     constexpr double spacingFactor = 0.5;
     196              : 
     197              :     // Ensure time tick segments are created
     198            0 :     EditTimeTickAnchors::updateAnchors(dynamic);
     199              : 
     200              :     // Find segment of type ChordRest or TimeTick near cursor postion
     201            0 :     score->dragPosition(pos, &staffIndex, &seg, spacingFactor, /*allowTimeAnchor*/ true);
     202              : 
     203            0 :     const bool hasValidTick = seg && (isLeftGrip
     204            0 :                                       ? seg->tick() < dynamic->tick()
     205            0 :                                       : seg->tick() > dynamic->tick());
     206            0 :     if (!hasValidTick) {
     207            0 :         return nullptr;
     208              :     }
     209              : 
     210            0 :     Hairpin* hairpin = Factory::createHairpin(score->dummy());
     211            0 :     hairpin->setHairpinType(isLeftGrip ? HairpinType::DIM_HAIRPIN : HairpinType::CRESC_HAIRPIN);
     212              : 
     213            0 :     hairpin->setTrack(track);
     214            0 :     hairpin->setTrack2(track);
     215              : 
     216            0 :     if (isLeftGrip) {
     217            0 :         hairpin->setTick(seg->tick());
     218            0 :         hairpin->setTick2(dynamic->tick());
     219              :     } else {
     220            0 :         hairpin->setTick(dynamic->tick());
     221            0 :         hairpin->setTick2(seg->tick());
     222              :     }
     223              : 
     224            0 :     hairpin->setVoiceAssignment(dynamic->voiceAssignment());
     225              : 
     226            0 :     score->undoAddElement(hairpin);
     227              : 
     228            0 :     return hairpin;
     229              : }
        

Generated by: LCOV version 2.0-1