From 20d07783ef05c511bdb9b14dbff215633c53174a Mon Sep 17 00:00:00 2001 From: sammik Date: Thu, 21 Sep 2023 02:00:12 +0200 Subject: [PATCH] fix #19373 move all hairpins; insert measure always acts in master score --- src/engraving/dom/box.cpp | 18 +- src/engraving/dom/edit.cpp | 341 +++++--------------------- src/engraving/dom/excerpt.cpp | 5 +- src/engraving/dom/joinMeasure.cpp | 2 +- src/engraving/dom/masterscore.cpp | 292 ++++++++++++++++++++++ src/engraving/dom/masterscore.h | 2 + src/engraving/dom/score.h | 5 +- src/engraving/dom/splitMeasure.cpp | 4 +- src/engraving/tests/measure_tests.cpp | 20 +- src/engraving/tests/parts_tests.cpp | 4 +- 10 files changed, 385 insertions(+), 308 deletions(-) diff --git a/src/engraving/dom/box.cpp b/src/engraving/dom/box.cpp index 113bc77f6c240..1d4cdaf664d53 100644 --- a/src/engraving/dom/box.cpp +++ b/src/engraving/dom/box.cpp @@ -430,7 +430,23 @@ void Box::manageExclusionFromParts(bool exclude) if (score == this->score()) { continue; } - MeasureBase* newFrame = score->insertMeasure(type(), next()); + MeasureBase* newMB = nullptr; + if (!excludeFromOtherParts()) { + for (auto e : linkList()) { + if (e->score() == score) { + newMB = toMeasureBase(e); + break; + } + } + } + // no linked frame found in score; use measure as insert point + if (!newMB) { + newMB = score->tick2measure(tick()); + } + if (!newMB) { + LOGD("measure base not found in score"); + } + MeasureBase* newFrame = score->insertMeasure(type(), newMB); newFrame->setExcludeFromOtherParts(false); newFrames.push_back(newFrame); } diff --git a/src/engraving/dom/edit.cpp b/src/engraving/dom/edit.cpp index 44ce0f88b8ab5..f52d627dc4572 100644 --- a/src/engraving/dom/edit.cpp +++ b/src/engraving/dom/edit.cpp @@ -29,7 +29,6 @@ #include "articulation.h" #include "barline.h" #include "beam.h" -#include "box.h" #include "bracket.h" #include "breath.h" #include "chord.h" @@ -666,7 +665,7 @@ Slur* Score::addSlur(ChordRest* firstChordRest, ChordRest* secondChordRest, cons return slur; } -TextBase* Score::addText(TextStyleType type, EngravingItem* destinationElement, bool addToAllScores) +TextBase* Score::addText(TextStyleType type, EngravingItem* destinationElement) { TextBase* textBox = nullptr; @@ -681,13 +680,20 @@ TextBase* Score::addText(TextStyleType type, EngravingItem* destinationElement, if (destinationElement && destinationElement->isVBox()) { frame = toMeasureBase(destinationElement); } else { - frame = first(); - - if (!frame || !frame->isVBox()) { - InsertMeasureOptions options; - options.addToAllScores = addToAllScores; - - frame = insertMeasure(ElementType::VBOX, frame, options); + MeasureBase* linkedFrame = nullptr; + for (Score* score : scoreList()) { + MeasureBase* titleFrame = score->first(); + if (!titleFrame || !titleFrame->isVBox()) { + titleFrame = score->insertMeasure(ElementType::VBOX, titleFrame); + } + if (!linkedFrame) { + linkedFrame = titleFrame; + } else { + score->undo(new Link(titleFrame, linkedFrame)); + } + if (score == this->score()) { + frame = titleFrame; + } } } @@ -3965,315 +3971,78 @@ void Score::nextInputPos(ChordRest* cr, bool doSelect) //--------------------------------------------------------- // insertMeasure -// Create a new MeasureBase of type type and insert -// before measure. -// If measure is zero, append new MeasureBase. +// if inserting Measure, act on master score +// (and add to all linked scores) +// if inserting Box, add to local score only //--------------------------------------------------------- MeasureBase* Score::insertMeasure(ElementType type, MeasureBase* beforeMeasure, const InsertMeasureOptions& options) { + MeasureBase* localInsertMeasureBase = nullptr; + if (type == ElementType::MEASURE) { + if (MeasureBase* masterInsertMeasure = masterScore()->insertMeasure(beforeMeasure, options)) { + localInsertMeasureBase = tick2measureBase(masterInsertMeasure->tick()); + } + } else { + localInsertMeasureBase = insertBox(type, beforeMeasure, options); + } + + return localInsertMeasureBase; +} + +//--------------------------------------------------------- +// insertBox +//--------------------------------------------------------- + +MeasureBase* Score::insertBox(ElementType type, MeasureBase* beforeMeasure, const InsertMeasureOptions& options) +{ + const bool isFrame = type == ElementType::FBOX || type == ElementType::HBOX || type == ElementType::TBOX || type == ElementType::VBOX; + + if (!isFrame) { + return nullptr; + } + Fraction tick; if (beforeMeasure) { if (beforeMeasure->isMeasure()) { - if (toMeasure(beforeMeasure)->isMMRest()) { - beforeMeasure = toMeasure(beforeMeasure)->prev(); - beforeMeasure = beforeMeasure ? beforeMeasure->next() : firstMeasure(); + Measure* m = toMeasure(beforeMeasure); + if (m->isMMRest()) { + beforeMeasure = m->mmRestFirst(); deselectAll(); } for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) { - if (toMeasure(beforeMeasure)->isMeasureRepeatGroupWithPrevM(staffIdx)) { + if (m->isMeasureRepeatGroupWithPrevM(staffIdx)) { MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT); return nullptr; } } + } else { + beforeMeasure = beforeMeasure->top(); // don't try to insert in front of nested frame } tick = beforeMeasure->tick(); } else { tick = last() ? last()->endTick() : Fraction(0, 1); } - const Fraction currentTimeSig = sigmap()->timesig(tick.ticks()).nominal(); // use nominal time signature of current measure - Measure* localMeasure = nullptr; // measure base in "this" score - MeasureBase* linkedMasterMeasure = nullptr; // measure base in root score (for linking) - Fraction ticks = { 0, 1 }; - - MeasureBase* result = nullptr; const bool isBeginning = tick.isZero(); - const bool isFrame = type == ElementType::FBOX || type == ElementType::HBOX || type == ElementType::TBOX || type == ElementType::VBOX; const bool isTitleFrame = (type == ElementType::VBOX || type == ElementType::TBOX) && isBeginning; const bool dontCloneFrameToParts = isFrame && !isTitleFrame; - std::list scores; - if (options.addToAllScores && !dontCloneFrameToParts) { - scores = scoreList(); - } else { - scores.push_back(this); - } - - for (Score* score : scores) { - MeasureBase* actualBeforeMeasure = nullptr; + MeasureBase* newMeasureBase = toMeasureBase(Factory::createItem(type, dummy())); + newMeasureBase->setTick(tick); + newMeasureBase->setExcludeFromOtherParts(dontCloneFrameToParts); - if (beforeMeasure) { - if (beforeMeasure->score() == score) { - actualBeforeMeasure = beforeMeasure; - } else if (beforeMeasure->isMeasure()) { - actualBeforeMeasure = score->tick2measure(tick); - } else if (beforeMeasure->links()) { - for (EngravingObject* m : *beforeMeasure->links()) { - if (m && m->isMeasureBase() && m->score() == score) { - actualBeforeMeasure = toMeasureBase(m); - break; - } - } - } + newMeasureBase->setNext(beforeMeasure); + newMeasureBase->setPrev(beforeMeasure ? beforeMeasure->prev() : last()); - if (!actualBeforeMeasure) { - LOGD("measure not found"); - } - } - - MeasureBase* newMeasureBase = toMeasureBase(Factory::createItem(type, score->dummy())); - newMeasureBase->setTick(tick); - newMeasureBase->setExcludeFromOtherParts(dontCloneFrameToParts); - - if (score == this) { - result = newMeasureBase; - } - - if (actualBeforeMeasure) { - actualBeforeMeasure = actualBeforeMeasure->top(); // don't try to insert in front of nested frame - } - newMeasureBase->setNext(actualBeforeMeasure); - newMeasureBase->setPrev(actualBeforeMeasure ? actualBeforeMeasure->prev() : score->last()); - if (newMeasureBase->isMeasure()) { - Measure* m = toMeasure(newMeasureBase); - m->setTimesig(currentTimeSig); - m->setTicks(currentTimeSig); - } - undo(new InsertMeasures(newMeasureBase, newMeasureBase)); - - if (type == ElementType::MEASURE) { - Measure* newMeasure = toMeasure(newMeasureBase); // new measure - ticks = newMeasure->ticks(); - Measure* measureInsert = nullptr; // insert before - if (actualBeforeMeasure) { - if (actualBeforeMeasure->isMeasure()) { - measureInsert = toMeasure(actualBeforeMeasure); - } else { - measureInsert = score->tick2measure(actualBeforeMeasure->tick()); - } - } - - if (score->isMaster()) { - localMeasure = newMeasure; - } - - std::vector timeSigList; - std::vector keySigList; - std::vector clefList; - std::vector previousClefList; - std::list specialCaseClefs; - std::vector previousBarLinesList; - - Measure* pm = newMeasure->prevMeasure(); - - // - // remove clef, barlines, time and key signatures - // - if (measureInsert) { - // if inserting before first measure, always preserve clefs and signatures - // at the begining of the score (move them back) - if (pm && !options.moveSignaturesClef && !isBeginning) { - Segment* ps = pm->findSegment(SegmentType::Clef, tick); - if (ps && ps->enabled()) { - for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { - EngravingItem* pc = ps->element(staffIdx * VOICES); - if (pc) { - previousClefList.push_back(toClef(pc)); - undo(new RemoveElement(pc)); - if (ps->empty()) { - undoRemoveElement(ps); - } - } - } - } - } - - if (options.moveSignaturesClef || isBeginning) { - for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { - for (Segment* s = measureInsert->first(); s && s->rtick().isZero(); s = s->next()) { - if (!s->enabled()) { - continue; - } - EngravingItem* e = s->element(staffIdx * VOICES); - // if it's a clef, we only add if it's a header clef - bool moveClef = s->isHeaderClefType() && e && e->isClef() && !toClef(e)->forInstrumentChange(); - // otherwise, we only add if e exists and is generated - bool moveOther = e && !e->isClef() && (!e->generated() || tick.isZero()); - bool specialCase = false; - if (e && e->isClef() && !moveClef && isBeginning - && toClef(e)->clefToBarlinePosition() != ClefToBarlinePosition::AFTER) { - // special case: - // there is a non-header clef at global tick 0, and we are inserting at the beginning of the score. - // this clef will be moved with the measure it accompanies, but it will be moved before the barline. - specialCase = true; - moveClef = true; - } - if (!moveClef && !moveOther) { - continue; // this item will remain with the old measure - } - // otherwise, this item is moved back to the new measure - EngravingItem* ee = 0; - if (e->isKeySig()) { - KeySig* ks = toKeySig(e); - if (ks->forInstrumentChange()) { - continue; - } - keySigList.push_back(ks); - // if instrument change on that place, set correct key signature for instrument change - bool ic = s->next(SegmentType::ChordRest)->findAnnotation(ElementType::INSTRUMENT_CHANGE, - e->part()->startTrack(), - e->part()->endTrack() - 1); - if (ic) { - KeySigEvent ke = ks->keySigEvent(); - ke.setForInstrumentChange(true); - undoChangeKeySig(ks->staff(), e->tick(), ke); - } else { - ee = e; - } - } else if (e->isTimeSig()) { - TimeSig* ts = toTimeSig(e); - timeSigList.push_back(ts); - ee = e; - } - if (specialCase) { - specialCaseClefs.push_back(toClef(e)); - ee = e; - } else if (tick.isZero() && e->isClef()) { - Clef* clef = toClef(e); - clefList.push_back(clef); - ee = e; - } - if (ee) { - undo(new RemoveElement(ee)); - if (s->empty()) { - undoRemoveElement(s); - } - } - } - } - - if (localMeasure && measureInsert->repeatStart()) { - localMeasure->undoChangeProperty(Pid::REPEAT_START, true); - measureInsert->undoChangeProperty(Pid::REPEAT_START, false); - } - } - } else if (!measureInsert && tick == Fraction(0, 1)) { - // If inserting measure into an empty score, restore default C key signature - // and 4/4 time signature - score->restoreInitialKeySigAndTimeSig(); - } - - if (pm && !options.moveSignaturesClef) { - Segment* pbs = pm->findSegment(SegmentType::EndBarLine, tick); - if (pbs && pbs->enabled()) { - for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { - EngravingItem* pb = pbs->element(staffIdx * VOICES); - if (pb && !pb->generated()) { - previousBarLinesList.push_back(toBarLine(pb)); - undo(new RemoveElement(pb)); - if (pbs->empty()) { - pbs->setEnabled(false); - } - } - } - } - if (localMeasure && pm->repeatEnd()) { - localMeasure->undoChangeProperty(Pid::REPEAT_END, true); - pm->undoChangeProperty(Pid::REPEAT_END, false); - } - } - - // - // move clef, barline, time, key signatures - // - for (TimeSig* ts : timeSigList) { - TimeSig* nts = Factory::copyTimeSig(*ts); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1)); - nts->setParent(s); - undoAddElement(nts); - } - for (KeySig* ks : keySigList) { - KeySig* nks = Factory::copyKeySig(*ks); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1)); - nks->setParent(s); - if (!nks->isAtonal()) { - nks->setKey(nks->concertKey()); // to set correct (transposing) key - } - undoAddElement(nks); - } - for (Clef* clef : clefList) { - Clef* nClef = Factory::copyClef(*clef); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::HeaderClef, Fraction(0, 1)); - nClef->setParent(s); - undoAddElement(nClef); - } - for (Clef* clef : previousClefList) { - Clef* nClef = Factory::copyClef(*clef); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks()); - nClef->setParent(s); - undoAddElement(nClef); - } - for (Clef* clef : specialCaseClefs) { - Clef* nClef = Factory::copyClef(*clef); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks()); - nClef->setParent(s); - undoAddElement(nClef); - } - for (BarLine* barLine : previousBarLinesList) { - BarLine* nBarLine = Factory::copyBarLine(*barLine); - Segment* s = newMeasure->undoGetSegmentR(SegmentType::EndBarLine, newMeasure->ticks()); - nBarLine->setParent(s); - undoAddElement(nBarLine); - } - } else { - // a frame, not a measure - if (score->isMaster()) { - linkedMasterMeasure = newMeasureBase; - } else if (linkedMasterMeasure && newMeasureBase != linkedMasterMeasure) { - newMeasureBase->linkTo(linkedMasterMeasure); - if (linkedMasterMeasure->isTBox()) { - toTBox(newMeasureBase)->text()->linkTo(toTBox(linkedMasterMeasure)->text()); - } - } - } - } - - undoInsertTime(tick, ticks); - - if (localMeasure && !options.createEmptyMeasures) { - // - // fill measure with rest - // - Score* score = localMeasure->score(); - - // add rest to all staves and to all the staves linked to it - for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { - size_t track = staffIdx * VOICES; - Rest* rest = Factory::createRest(score->dummy()->segment(), TDuration(DurationType::V_MEASURE)); - Fraction timeStretch(score->staff(staffIdx)->timeStretch(localMeasure->tick())); - rest->setTicks(localMeasure->ticks() * timeStretch); - rest->setTrack(track); - score->undoAddCR(rest, localMeasure, tick); - } - } + undo(new InsertMeasures(newMeasureBase, newMeasureBase)); if (options.needDeselectAll) { deselectAll(); } - return result; + return newMeasureBase; } void Score::restoreInitialKeySigAndTimeSig() diff --git a/src/engraving/dom/excerpt.cpp b/src/engraving/dom/excerpt.cpp index 97187f6c46339..5145b5f277bb6 100644 --- a/src/engraving/dom/excerpt.cpp +++ b/src/engraving/dom/excerpt.cpp @@ -348,10 +348,7 @@ void Excerpt::createExcerpt(Excerpt* excerpt) MeasureBase* scoreMeasure = score->first(); if ((!scoreMeasure || !scoreMeasure->isVBox()) && !masterMeasure->excludeFromOtherParts()) { - Score::InsertMeasureOptions options; - options.addToAllScores = false; - - score->insertMeasure(ElementType::VBOX, scoreMeasure, options); + score->insertMeasure(ElementType::VBOX, scoreMeasure); scoreMeasure = score->first(); } diff --git a/src/engraving/dom/joinMeasure.cpp b/src/engraving/dom/joinMeasure.cpp index c3b710a2934ea..2d6dfcf1ce9bf 100644 --- a/src/engraving/dom/joinMeasure.cpp +++ b/src/engraving/dom/joinMeasure.cpp @@ -100,7 +100,7 @@ void MasterScore::joinMeasure(const Fraction& tick1, const Fraction& tick2) InsertMeasureOptions options; options.createEmptyMeasures = true; options.moveSignaturesClef = false; - insertMeasure(ElementType::MEASURE, next, options); + insertMeasure(next, options); for (Score* s : scoreList()) { Measure* sM1 = s->tick2measure(startTick); diff --git a/src/engraving/dom/masterscore.cpp b/src/engraving/dom/masterscore.cpp index 98ceb5509cd67..409ec635086c2 100644 --- a/src/engraving/dom/masterscore.cpp +++ b/src/engraving/dom/masterscore.cpp @@ -35,10 +35,15 @@ #include "engravingproject.h" #include "audio.h" +#include "barline.h" #include "excerpt.h" +#include "factory.h" +#include "linkedobjects.h" #include "repeatlist.h" +#include "rest.h" #include "sig.h" #include "tempo.h" +#include "timesig.h" #include "undo.h" #include "log.h" @@ -464,3 +469,290 @@ void MasterScore::rebuildAndUpdateExpressive(Synthesizer* synth) // Rebuild midi mappings again to be safe rebuildMidiMapping(); } + +//--------------------------------------------------------- +// insertMeasure +// Create a new MeasureBase of type type and insert +// before measure. +// If measure is zero, append new MeasureBase. +//--------------------------------------------------------- + +MeasureBase* MasterScore::insertMeasure(MeasureBase* beforeMeasure, const InsertMeasureOptions& options) +{ + Fraction tick; + if (beforeMeasure) { + if (beforeMeasure->isMeasure()) { + if (toMeasure(beforeMeasure)->isMMRest()) { + beforeMeasure = toMeasure(beforeMeasure)->prev(); + beforeMeasure = beforeMeasure ? beforeMeasure->next() : firstMeasure(); + deselectAll(); + } + for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) { + if (toMeasure(beforeMeasure)->isMeasureRepeatGroupWithPrevM(staffIdx)) { + MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT); + return nullptr; + } + } + } + tick = beforeMeasure->tick(); + } else { + tick = last() ? last()->endTick() : Fraction(0, 1); + } + + const Fraction currentTimeSig = sigmap()->timesig(tick.ticks()).nominal(); // use nominal time signature of current measure + Measure* masterMeasure = nullptr; + Fraction ticks = { 0, 1 }; + + MeasureBase* result = nullptr; + const bool isBeginning = tick.isZero(); + + for (Score* score : scoreList()) { + MeasureBase* actualBeforeMeasure = nullptr; + + if (beforeMeasure) { + if (beforeMeasure->score() == score) { + actualBeforeMeasure = beforeMeasure; + } else if (!beforeMeasure->isMeasure() && beforeMeasure->links()) { + for (EngravingObject* m : *beforeMeasure->links()) { + if (m && m->isMeasureBase() && m->score() == score) { + actualBeforeMeasure = toMeasureBase(m); + break; + } + } + } + // if beforeMeasure is measure; or if din't find linked frame, use measure + if (!actualBeforeMeasure) { + actualBeforeMeasure = score->tick2measure(tick); + } + + if (!actualBeforeMeasure) { + LOGD("measure not found"); + } + } + + MeasureBase* newMeasureBase = toMeasureBase(Factory::createMeasure(score->dummy()->system())); + newMeasureBase->setTick(tick); + + if (score == this) { + result = newMeasureBase; + } + + if (actualBeforeMeasure) { + actualBeforeMeasure = actualBeforeMeasure->top(); // don't try to insert in front of nested frame + } + newMeasureBase->setNext(actualBeforeMeasure); + newMeasureBase->setPrev(actualBeforeMeasure ? actualBeforeMeasure->prev() : score->last()); + if (newMeasureBase->isMeasure()) { + Measure* m = toMeasure(newMeasureBase); + m->setTimesig(currentTimeSig); + m->setTicks(currentTimeSig); + } + undo(new InsertMeasures(newMeasureBase, newMeasureBase)); + + Measure* newMeasure = toMeasure(newMeasureBase); // new measure + ticks = newMeasure->ticks(); + Measure* measureInsert = nullptr; // insert before + if (actualBeforeMeasure) { + if (actualBeforeMeasure->isMeasure()) { + measureInsert = toMeasure(actualBeforeMeasure); + } else { + measureInsert = score->tick2measure(actualBeforeMeasure->tick()); + } + } + + if (score->isMaster()) { + masterMeasure = newMeasure; + } + + std::vector timeSigList; + std::vector keySigList; + std::vector clefList; + std::vector previousClefList; + std::list specialCaseClefs; + std::vector previousBarLinesList; + + Measure* pm = newMeasure->prevMeasure(); + + // + // remove clef, barlines, time and key signatures + // + if (measureInsert) { + // if inserting before first measure, always preserve clefs and signatures + // at the begining of the score (move them back) + if (pm && !options.moveSignaturesClef && !isBeginning) { + Segment* ps = pm->findSegment(SegmentType::Clef, tick); + if (ps && ps->enabled()) { + for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + EngravingItem* pc = ps->element(staffIdx * VOICES); + if (pc) { + previousClefList.push_back(toClef(pc)); + undo(new RemoveElement(pc)); + if (ps->empty()) { + undoRemoveElement(ps); + } + } + } + } + } + + if (options.moveSignaturesClef || isBeginning) { + for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + for (Segment* s = measureInsert->first(); s && s->rtick().isZero(); s = s->next()) { + if (!s->enabled()) { + continue; + } + EngravingItem* e = s->element(staffIdx * VOICES); + // if it's a clef, we only add if it's a header clef + bool moveClef = s->isHeaderClefType() && e && e->isClef() && !toClef(e)->forInstrumentChange(); + // otherwise, we only add if e exists and is generated + bool moveOther = e && !e->isClef() && (!e->generated() || tick.isZero()); + bool specialCase = false; + if (e && e->isClef() && !moveClef && isBeginning + && toClef(e)->clefToBarlinePosition() != ClefToBarlinePosition::AFTER) { + // special case: + // there is a non-header clef at global tick 0, and we are inserting at the beginning of the score. + // this clef will be moved with the measure it accompanies, but it will be moved before the barline. + specialCase = true; + moveClef = true; + } + if (!moveClef && !moveOther) { + continue; // this item will remain with the old measure + } + // otherwise, this item is moved back to the new measure + EngravingItem* ee = 0; + if (e->isKeySig()) { + KeySig* ks = toKeySig(e); + if (ks->forInstrumentChange()) { + continue; + } + keySigList.push_back(ks); + // if instrument change on that place, set correct key signature for instrument change + bool ic = s->next(SegmentType::ChordRest)->findAnnotation(ElementType::INSTRUMENT_CHANGE, + e->part()->startTrack(), + e->part()->endTrack() - 1); + if (ic) { + KeySigEvent ke = ks->keySigEvent(); + ke.setForInstrumentChange(true); + undoChangeKeySig(ks->staff(), e->tick(), ke); + } else { + ee = e; + } + } else if (e->isTimeSig()) { + TimeSig* ts = toTimeSig(e); + timeSigList.push_back(ts); + ee = e; + } + if (specialCase) { + specialCaseClefs.push_back(toClef(e)); + ee = e; + } else if (tick.isZero() && e->isClef()) { + Clef* clef = toClef(e); + clefList.push_back(clef); + ee = e; + } + if (ee) { + undo(new RemoveElement(ee)); + if (s->empty()) { + undoRemoveElement(s); + } + } + } + } + + if (masterMeasure && measureInsert->repeatStart()) { + masterMeasure->undoChangeProperty(Pid::REPEAT_START, true); + measureInsert->undoChangeProperty(Pid::REPEAT_START, false); + } + } + } else if (!measureInsert && tick == Fraction(0, 1)) { + // If inserting measure into an empty score, restore default C key signature + // and 4/4 time signature + score->restoreInitialKeySigAndTimeSig(); + } + + if (pm && !options.moveSignaturesClef) { + Segment* pbs = pm->findSegment(SegmentType::EndBarLine, tick); + if (pbs && pbs->enabled()) { + for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + EngravingItem* pb = pbs->element(staffIdx * VOICES); + if (pb && !pb->generated()) { + previousBarLinesList.push_back(toBarLine(pb)); + undo(new RemoveElement(pb)); + if (pbs->empty()) { + pbs->setEnabled(false); + } + } + } + } + if (masterMeasure && pm->repeatEnd()) { + masterMeasure->undoChangeProperty(Pid::REPEAT_END, true); + pm->undoChangeProperty(Pid::REPEAT_END, false); + } + } + + // + // move clef, barline, time, key signatures + // + for (TimeSig* ts : timeSigList) { + TimeSig* nts = Factory::copyTimeSig(*ts); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1)); + nts->setParent(s); + undoAddElement(nts); + } + for (KeySig* ks : keySigList) { + KeySig* nks = Factory::copyKeySig(*ks); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1)); + nks->setParent(s); + if (!nks->isAtonal()) { + nks->setKey(nks->concertKey()); // to set correct (transposing) key + } + undoAddElement(nks); + } + for (Clef* clef : clefList) { + Clef* nClef = Factory::copyClef(*clef); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::HeaderClef, Fraction(0, 1)); + nClef->setParent(s); + undoAddElement(nClef); + } + for (Clef* clef : previousClefList) { + Clef* nClef = Factory::copyClef(*clef); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks()); + nClef->setParent(s); + undoAddElement(nClef); + } + for (Clef* clef : specialCaseClefs) { + Clef* nClef = Factory::copyClef(*clef); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks()); + nClef->setParent(s); + undoAddElement(nClef); + } + for (BarLine* barLine : previousBarLinesList) { + BarLine* nBarLine = Factory::copyBarLine(*barLine); + Segment* s = newMeasure->undoGetSegmentR(SegmentType::EndBarLine, newMeasure->ticks()); + nBarLine->setParent(s); + undoAddElement(nBarLine); + } + } + + undoInsertTime(tick, ticks); + + if (masterMeasure && !options.createEmptyMeasures) { + // + // fill measure with rest + // undoAddCR adds rest to linked staves as well + for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) { + size_t track = staffIdx * VOICES; + Rest* rest = Factory::createRest(dummy()->segment(), TDuration(DurationType::V_MEASURE)); + Fraction timeStretch(staff(staffIdx)->timeStretch(masterMeasure->tick())); + rest->setTicks(masterMeasure->ticks() * timeStretch); + rest->setTrack(track); + undoAddCR(rest, masterMeasure, tick); + } + } + + if (options.needDeselectAll) { + deselectAll(); + } + + return result; +} diff --git a/src/engraving/dom/masterscore.h b/src/engraving/dom/masterscore.h index ce372a26e1334..5cd8abe607ee4 100644 --- a/src/engraving/dom/masterscore.h +++ b/src/engraving/dom/masterscore.h @@ -218,6 +218,8 @@ class MasterScore : public Score void splitMeasure(const Fraction&); void joinMeasure(const Fraction&, const Fraction&); + MeasureBase* insertMeasure(MeasureBase* beforeMeasure = nullptr, const InsertMeasureOptions& options = InsertMeasureOptions()); + IFileInfoProviderPtr fileInfo() const; void setFileInfoProvider(IFileInfoProviderPtr fileInfoProvider); diff --git a/src/engraving/dom/score.h b/src/engraving/dom/score.h index 64cf2c0e34b6b..5901ee92caefc 100644 --- a/src/engraving/dom/score.h +++ b/src/engraving/dom/score.h @@ -460,7 +460,7 @@ class Score : public EngravingObject NoteVal noteValForPosition(Position pos, AccidentalType at, bool& error); Slur* addSlur(ChordRest* firstChordRest, ChordRest* secondChordRest, const Slur* slurTemplate); - TextBase* addText(TextStyleType type, EngravingItem* destinationElement = nullptr, bool addToAllScores = true); + TextBase* addText(TextStyleType type, EngravingItem* destinationElement = nullptr); void deleteItem(EngravingItem*); void deleteMeasures(MeasureBase* firstMeasure, MeasureBase* lastMeasure, bool preserveTies = false); @@ -826,11 +826,12 @@ class Score : public EngravingObject bool createEmptyMeasures = false; bool moveSignaturesClef = true; bool needDeselectAll = true; - bool addToAllScores = true; }; MeasureBase* insertMeasure(ElementType type, MeasureBase* beforeMeasure = nullptr, const InsertMeasureOptions& options = InsertMeasureOptions()); + MeasureBase* insertBox(ElementType type, MeasureBase* beforeMeasure = nullptr, + const InsertMeasureOptions& options = InsertMeasureOptions()); Audio* audio() const { return m_audio; } void setAudio(Audio* a) { m_audio = a; } diff --git a/src/engraving/dom/splitMeasure.cpp b/src/engraving/dom/splitMeasure.cpp index 9ef99d225afc8..ad98f0f9aa99c 100644 --- a/src/engraving/dom/splitMeasure.cpp +++ b/src/engraving/dom/splitMeasure.cpp @@ -115,9 +115,9 @@ void MasterScore::splitMeasure(const Fraction& tick) options.createEmptyMeasures = true; options.moveSignaturesClef = false; - insertMeasure(ElementType::MEASURE, nm, options); + insertMeasure(nm, options); Measure* m2 = toMeasure(nm ? nm->prev() : lastMeasure()); - insertMeasure(ElementType::MEASURE, m2, options); + insertMeasure(m2, options); Measure* m1 = toMeasure(m2->prev()); for (Score* s : scoreList()) { diff --git a/src/engraving/tests/measure_tests.cpp b/src/engraving/tests/measure_tests.cpp index 5a8b410035c26..6c86d499ec803 100644 --- a/src/engraving/tests/measure_tests.cpp +++ b/src/engraving/tests/measure_tests.cpp @@ -49,7 +49,7 @@ TEST_F(Engraving_MeasureTests, DISABLED_insertMeasureMiddle) //TODO: verify prog score->startCmd(); Measure* m = score->firstMeasure()->nextMeasure(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-1.mscx", MEASURE_DATA_DIR + u"measure-1-ref.mscx")); @@ -63,7 +63,7 @@ TEST_F(Engraving_MeasureTests, DISABLED_insertMeasureBegin) // TODO: verify prog score->startCmd(); Measure* m = score->firstMeasure(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-2.mscx", MEASURE_DATA_DIR + u"measure-2-ref.mscx")); @@ -76,7 +76,7 @@ TEST_F(Engraving_MeasureTests, DISABLED_insertMeasureEnd) // TODO: verify progra EXPECT_TRUE(score); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, 0); + score->insertMeasure(0); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-3.mscx", MEASURE_DATA_DIR + u"measure-3-ref.mscx")); @@ -89,7 +89,7 @@ TEST_F(Engraving_MeasureTests, insertAtBeginning) EXPECT_TRUE(score); Measure* m = score->firstMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-insert_beginning.mscx", MEASURE_DATA_DIR + u"measure-insert_beginning-ref.mscx")); @@ -105,7 +105,7 @@ TEST_F(Engraving_MeasureTests, insertBfClefChange) Measure* m = score->firstMeasure()->nextMeasure(); m = m->nextMeasure()->nextMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-insert_bf_clef.mscx", MEASURE_DATA_DIR + u"measure-insert_bf_clef-ref.mscx")); @@ -116,7 +116,7 @@ TEST_F(Engraving_MeasureTests, insertBfClefChange) m = score->firstMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-insert_bf_clef-2.mscx", @@ -137,7 +137,7 @@ TEST_F(Engraving_MeasureTests, insertBfKeyChange) Measure* m = score->firstMeasure()->nextMeasure(); m = m->nextMeasure()->nextMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(score->checkKeys()); @@ -151,7 +151,7 @@ TEST_F(Engraving_MeasureTests, insertBfKeyChange) m = score->firstMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(score->checkKeys()); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-insert_bf_key-2.mscx", @@ -180,7 +180,7 @@ TEST_F(Engraving_MeasureTests, spanner_a) Measure* m = score->firstMeasure()->nextMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-4.mscx", MEASURE_DATA_DIR + u"measure-4-ref.mscx")); @@ -202,7 +202,7 @@ TEST_F(Engraving_MeasureTests, spanner_b) Measure* m = score->firstMeasure(); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"measure-5.mscx", MEASURE_DATA_DIR + u"measure-5-ref.mscx")); diff --git a/src/engraving/tests/parts_tests.cpp b/src/engraving/tests/parts_tests.cpp index 8057051a5a6f9..a930e95179541 100644 --- a/src/engraving/tests/parts_tests.cpp +++ b/src/engraving/tests/parts_tests.cpp @@ -239,7 +239,7 @@ TEST_F(Engraving_PartsTests, appendMeasure) createParts(score); score->startCmd(); - score->insertMeasure(ElementType::MEASURE, 0); + score->insertMeasure(0); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"part-all-appendmeasures.mscx", PARTS_DATA_DIR + u"part-all-appendmeasures.mscx")); @@ -263,7 +263,7 @@ TEST_F(Engraving_PartsTests, insertMeasure) score->startCmd(); Measure* m = score->firstMeasure(); - score->insertMeasure(ElementType::MEASURE, m); + score->insertMeasure(m); score->endCmd(); EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"part-all-insertmeasures.mscx", PARTS_DATA_DIR + u"part-all-insertmeasures.mscx"));