From 5f28d661f15da72867de676b2acf3a61d79a0ffe Mon Sep 17 00:00:00 2001 From: Igor Korsukov Date: Fri, 20 Aug 2021 14:10:03 +0200 Subject: [PATCH] removed libmscore/layout.cpp --- .../internal/applicationactioncontroller.cpp | 1 + src/engraving/libmscore/layout.cpp | 492 ---------------- src/engraving/libmscore/layout.h | 26 - src/engraving/libmscore/layout/layout.cpp | 488 +--------------- src/engraving/libmscore/layout/layout.h | 9 +- .../libmscore/layout/layoutbeams.cpp | 1 + .../libmscore/layout/layoutchords.cpp | 1 + .../libmscore/layout/layoutcontext.cpp | 305 +++++++++- .../libmscore/layout/layoutmeasure.cpp | 542 +++++++++++++++++- .../libmscore/layout/layoutmeasure.h | 6 + .../libmscore/layout/layouttuplets.cpp | 20 + .../libmscore/layout/layouttuplets.h | 1 + src/engraving/libmscore/layoutlinear.cpp | 54 -- src/engraving/libmscore/libmscore.cmake | 3 - src/engraving/libmscore/measure.cpp | 1 - src/engraving/libmscore/score.cpp | 70 ++- src/engraving/libmscore/score.h | 2 - src/engraving/libmscore/textbase.cpp | 1 + src/engraving/style/styledef.cpp | 1 - src/engraving/style/styledef.h | 1 - .../accessibility/dev/accessibledevmodel.cpp | 1 + src/framework/global/globalmodule.cpp | 1 + .../internal/platform/lin/alsamidiinport.cpp | 2 +- .../internal/platform/lin/alsamidiinport.h | 2 +- .../internal/platform/lin/alsamidioutport.cpp | 2 +- .../internal/platform/lin/alsamidioutport.h | 2 +- src/framework/midi/midimodule.cpp | 3 +- src/framework/ui/view/navigationpanel.cpp | 2 + src/notation/view/widgets/editstaff.cpp | 4 +- src/notation/view/widgets/editstyle.cpp | 3 +- 30 files changed, 933 insertions(+), 1114 deletions(-) delete mode 100644 src/engraving/libmscore/layout.cpp delete mode 100644 src/engraving/libmscore/layout.h delete mode 100644 src/engraving/libmscore/layoutlinear.cpp diff --git a/src/appshell/internal/applicationactioncontroller.cpp b/src/appshell/internal/applicationactioncontroller.cpp index b0ccc39fd3..8d585c2c51 100644 --- a/src/appshell/internal/applicationactioncontroller.cpp +++ b/src/appshell/internal/applicationactioncontroller.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "translation.h" diff --git a/src/engraving/libmscore/layout.cpp b/src/engraving/libmscore/layout.cpp deleted file mode 100644 index bf4cad488d..0000000000 --- a/src/engraving/libmscore/layout.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) 2021 MuseScore BVBA and others - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include "style/style.h" - -#include "accidental.h" -#include "barline.h" -#include "beam.h" -#include "box.h" -#include "chord.h" -#include "clef.h" -#include "element.h" -#include "fingering.h" -#include "glissando.h" -#include "harmony.h" -#include "key.h" -#include "keysig.h" -#include "layoutbreak.h" -#include "layout.h" -#include "lyrics.h" -#include "marker.h" -#include "measure.h" -#include "mmrestrange.h" -#include "mmrest.h" -#include "mscore.h" -#include "notedot.h" -#include "note.h" -#include "ottava.h" -#include "page.h" -#include "part.h" -#include "measurerepeat.h" -#include "score.h" -#include "scorefont.h" -#include "segment.h" -#include "sig.h" -#include "slur.h" -#include "staff.h" -#include "stem.h" -#include "stemslash.h" -#include "sticking.h" -#include "sym.h" -#include "system.h" -#include "text.h" -#include "tie.h" -#include "timesig.h" -#include "tremolo.h" -#include "tuplet.h" -#include "undo.h" -#include "utils.h" -#include "volta.h" -#include "breath.h" -#include "tempotext.h" -#include "systemdivider.h" -#include "hook.h" -#include "ambitus.h" -#include "hairpin.h" -#include "stafflines.h" -#include "articulation.h" -#include "bracket.h" -#include "spacer.h" -#include "fermata.h" -#include "measurenumber.h" - -#include "masterscore.h" - -using namespace mu; - -namespace Ms { -// #define PAGE_DEBUG - -#ifdef PAGE_DEBUG -#define PAGEDBG(...) qDebug(__VA_ARGS__) -#else -#define PAGEDBG(...) ; -#endif - -//--------------------------------------------------------- -// almostZero -//--------------------------------------------------------- - -static bool inline almostZero(qreal value) -{ - // 1e-3 is close enough to zero to see it as zero. - return value > -1e-3 && value < 1e-3; -} - -//--------------------------------------------------------- -// relayoutForStyles -/// some styles can't properly apply if score hasn't been laid out yet, -/// so temporarily disable them and then reenable after layout -/// (called during score load) -//--------------------------------------------------------- - -void Score::relayoutForStyles() -{ - std::vector stylesToTemporarilyDisable; - - for (Sid sid : { Sid::createMultiMeasureRests, Sid::mrNumberSeries }) { - // only necessary if boolean style is true - if (styleB(sid)) { - stylesToTemporarilyDisable.push_back(sid); - } - } - - if (!stylesToTemporarilyDisable.empty()) { - for (Sid sid : stylesToTemporarilyDisable) { - style().set(sid, false); // temporarily disable - } - doLayout(); - for (Sid sid : stylesToTemporarilyDisable) { - style().set(sid, true); // and immediately reenable - } - } -} - -//--------------------------------------------------------- -// createMMRest -// create a multimeasure rest -// from firstMeasure to lastMeasure (inclusive) -//--------------------------------------------------------- - -void Score::createMMRest(Measure* firstMeasure, Measure* lastMeasure, const Fraction& len) -{ - int numMeasuresInMMRest = 1; - if (firstMeasure != lastMeasure) { - for (Measure* m = firstMeasure->nextMeasure(); m; m = m->nextMeasure()) { - ++numMeasuresInMMRest; - m->setMMRestCount(-1); - if (m->mmRest()) { - undo(new ChangeMMRest(m, 0)); - } - if (m == lastMeasure) { - break; - } - } - } - - // mmrMeasure coexists with n undisplayed measures of rests - Measure* mmrMeasure = firstMeasure->mmRest(); - if (mmrMeasure) { - // reuse existing mmrest - if (mmrMeasure->ticks() != len) { - Segment* s = mmrMeasure->findSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks()); - // adjust length - mmrMeasure->setTicks(len); - // move existing end barline - if (s) { - s->setRtick(len); - } - } - mmrMeasure->removeSystemTrailer(); - } else { - mmrMeasure = new Measure(this); - mmrMeasure->setTicks(len); - mmrMeasure->setTick(firstMeasure->tick()); - undo(new ChangeMMRest(firstMeasure, mmrMeasure)); - } - mmrMeasure->setTimesig(firstMeasure->timesig()); - mmrMeasure->setPageBreak(lastMeasure->pageBreak()); - mmrMeasure->setLineBreak(lastMeasure->lineBreak()); - mmrMeasure->setMMRestCount(numMeasuresInMMRest); - mmrMeasure->setNo(firstMeasure->no()); - - // - // set mmrMeasure with same barline as last underlying measure - // - Segment* lastMeasureEndBarlineSeg = lastMeasure->findSegmentR(SegmentType::EndBarLine, lastMeasure->ticks()); - if (lastMeasureEndBarlineSeg) { - Segment* mmrEndBarlineSeg = mmrMeasure->undoGetSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks()); - for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) { - Element* e = lastMeasureEndBarlineSeg->element(staffIdx * VOICES); - if (e) { - bool generated = e->generated(); - if (!mmrEndBarlineSeg->element(staffIdx * VOICES)) { - Element* eClone = generated ? e->clone() : e->linkedClone(); - eClone->setGenerated(generated); - eClone->setParent(mmrEndBarlineSeg); - undoAddElement(eClone); - } else { - BarLine* mmrEndBarline = toBarLine(mmrEndBarlineSeg->element(staffIdx * VOICES)); - BarLine* lastMeasureEndBarline = toBarLine(e); - if (!generated && !mmrEndBarline->links()) { - undo(new Link(mmrEndBarline, lastMeasureEndBarline)); - } - if (mmrEndBarline->barLineType() != lastMeasureEndBarline->barLineType()) { - // change directly when generating mmrests, do not change underlying measures or follow links - undo(new ChangeProperty(mmrEndBarline, Pid::BARLINE_TYPE, - QVariant::fromValue(lastMeasureEndBarline->barLineType()), - PropertyFlags::NOSTYLE)); - undo(new ChangeProperty(mmrEndBarline, Pid::GENERATED, generated, PropertyFlags::NOSTYLE)); - } - } - } - } - } - - // - // if last underlying measure ends with clef change, show same at end of mmrest - // - Segment* lastMeasureClefSeg = lastMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, - lastMeasure->ticks()); - if (lastMeasureClefSeg) { - Segment* mmrClefSeg = mmrMeasure->undoGetSegment(lastMeasureClefSeg->segmentType(), lastMeasure->endTick()); - for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) { - const int track = staff2track(staffIdx); - Element* e = lastMeasureClefSeg->element(track); - if (e && e->isClef()) { - Clef* lastMeasureClef = toClef(e); - if (!mmrClefSeg->element(track)) { - Clef* mmrClef = lastMeasureClef->generated() ? lastMeasureClef->clone() : toClef( - lastMeasureClef->linkedClone()); - mmrClef->setParent(mmrClefSeg); - undoAddElement(mmrClef); - } else { - Clef* mmrClef = toClef(mmrClefSeg->element(track)); - mmrClef->setClefType(lastMeasureClef->clefType()); - mmrClef->setShowCourtesy(lastMeasureClef->showCourtesy()); - } - } - } - } - - mmrMeasure->setRepeatStart(firstMeasure->repeatStart() || lastMeasure->repeatStart()); - mmrMeasure->setRepeatEnd(firstMeasure->repeatEnd() || lastMeasure->repeatEnd()); - mmrMeasure->setSectionBreak(lastMeasure->sectionBreak()); - - // - // copy markers to mmrMeasure - // - ElementList oldList = mmrMeasure->takeElements(); - ElementList newList = lastMeasure->el(); - for (Element* e : firstMeasure->el()) { - if (e->isMarker()) { - newList.push_back(e); - } - } - for (Element* e : newList) { - bool found = false; - for (Element* ee : oldList) { - if (ee->type() == e->type() && ee->subtype() == e->subtype()) { - mmrMeasure->add(ee); - auto i = std::find(oldList.begin(), oldList.end(), ee); - if (i != oldList.end()) { - oldList.erase(i); - } - found = true; - break; - } - } - if (!found) { - mmrMeasure->add(e->clone()); - } - } - for (Element* e : oldList) { - delete e; - } - Segment* s = mmrMeasure->undoGetSegmentR(SegmentType::ChordRest, Fraction(0, 1)); - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - int track = staffIdx * VOICES; - if (s->element(track) == 0) { - MMRest* mmr = new MMRest(this); - mmr->setDurationType(TDuration::DurationType::V_MEASURE); - mmr->setTicks(mmrMeasure->ticks()); - mmr->setTrack(track); - mmr->setParent(s); - undo(new AddElement(mmr)); - } - } - - // - // further check for clefs - // - Segment* underlyingSeg = lastMeasure->findSegmentR(SegmentType::Clef, lastMeasure->ticks()); - Segment* mmrSeg = mmrMeasure->findSegment(SegmentType::Clef, lastMeasure->endTick()); - if (underlyingSeg) { - if (mmrSeg == 0) { - mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::Clef, lastMeasure->ticks()); - } - mmrSeg->setEnabled(underlyingSeg->enabled()); - mmrSeg->setTrailer(underlyingSeg->trailer()); - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - int track = staffIdx * VOICES; - Clef* clef = toClef(underlyingSeg->element(track)); - if (clef) { - if (mmrSeg->element(track) == 0) { - mmrSeg->add(clef->clone()); - } else { - //TODO: check if same clef - } - } - } - } else if (mmrSeg) { - // TODO: remove elements from mmrSeg? - undo(new RemoveElement(mmrSeg)); - } - - // - // check for time signature - // - underlyingSeg = firstMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1)); - mmrSeg = mmrMeasure->findSegment(SegmentType::TimeSig, firstMeasure->tick()); - if (underlyingSeg) { - if (mmrSeg == 0) { - mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1)); - } - mmrSeg->setEnabled(underlyingSeg->enabled()); - mmrSeg->setHeader(underlyingSeg->header()); - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - int track = staffIdx * VOICES; - TimeSig* underlyingTimeSig = toTimeSig(underlyingSeg->element(track)); - if (underlyingTimeSig) { - TimeSig* mmrTimeSig = toTimeSig(mmrSeg->element(track)); - if (!mmrTimeSig) { - mmrTimeSig = underlyingTimeSig->generated() ? underlyingTimeSig->clone() : toTimeSig( - underlyingTimeSig->linkedClone()); - mmrTimeSig->setParent(mmrSeg); - undo(new AddElement(mmrTimeSig)); - } else { - mmrTimeSig->setSig(underlyingTimeSig->sig(), underlyingTimeSig->timeSigType()); - mmrTimeSig->layout(); - } - } - } - } else if (mmrSeg) { - // TODO: remove elements from mmrSeg? - undo(new RemoveElement(mmrSeg)); - } - - // - // check for ambitus - // - underlyingSeg = firstMeasure->findSegmentR(SegmentType::Ambitus, Fraction(0, 1)); - mmrSeg = mmrMeasure->findSegment(SegmentType::Ambitus, firstMeasure->tick()); - if (underlyingSeg) { - if (mmrSeg == 0) { - mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::Ambitus, Fraction(0, 1)); - } - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - int track = staffIdx * VOICES; - Ambitus* underlyingAmbitus = toAmbitus(underlyingSeg->element(track)); - if (underlyingAmbitus) { - Ambitus* mmrAmbitus = toAmbitus(mmrSeg->element(track)); - if (!mmrAmbitus) { - mmrAmbitus = underlyingAmbitus->clone(); - mmrAmbitus->setParent(mmrSeg); - undo(new AddElement(mmrAmbitus)); - } else { - mmrAmbitus->initFrom(underlyingAmbitus); - mmrAmbitus->layout(); - } - } - } - } else if (mmrSeg) { - // TODO: remove elements from mmrSeg? - undo(new RemoveElement(mmrSeg)); - } - - // - // check for key signature - // - underlyingSeg = firstMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1)); - mmrSeg = mmrMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1)); - if (underlyingSeg) { - if (mmrSeg == 0) { - mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1)); - } - mmrSeg->setEnabled(underlyingSeg->enabled()); - mmrSeg->setHeader(underlyingSeg->header()); - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - int track = staffIdx * VOICES; - KeySig* underlyingKeySig = toKeySig(underlyingSeg->element(track)); - if (underlyingKeySig) { - KeySig* mmrKeySig = toKeySig(mmrSeg->element(track)); - if (!mmrKeySig) { - mmrKeySig = underlyingKeySig->generated() ? underlyingKeySig->clone() : toKeySig( - underlyingKeySig->linkedClone()); - mmrKeySig->setParent(mmrSeg); - mmrKeySig->setGenerated(true); - undo(new AddElement(mmrKeySig)); - } else { - if (!(mmrKeySig->keySigEvent() == underlyingKeySig->keySigEvent())) { - bool addKey = underlyingKeySig->isChange(); - undo(new ChangeKeySig(mmrKeySig, underlyingKeySig->keySigEvent(), mmrKeySig->showCourtesy(), - addKey)); - } - } - } - } - } else if (mmrSeg) { - mmrSeg->setEnabled(false); - // TODO: remove elements from mmrSeg, then delete mmrSeg - // previously we removed the segment if not empty, - // but this resulted in "stale" keysig in mmrest after removed from underlying measure - //undo(new RemoveElement(mmrSeg)); - } - - mmrMeasure->checkHeader(); - mmrMeasure->checkTrailer(); - - // - // check for rehearsal mark etc. - // - underlyingSeg = firstMeasure->findSegmentR(SegmentType::ChordRest, Fraction(0, 1)); - if (underlyingSeg) { - // clone elements from underlying measure to mmr - for (Element* e : underlyingSeg->annotations()) { - // look at elements in underlying measure - if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() - || e->isInstrumentChange())) { - continue; - } - // try to find a match in mmr - bool found = false; - for (Element* ee : s->annotations()) { - if (e->linkList().contains(ee)) { - found = true; - break; - } - } - // add to mmr if no match found - if (!found) { - Element* eClone = e->linkedClone(); - eClone->setParent(s); - undo(new AddElement(eClone)); - } - } - - // remove stray elements (possibly leftover from a previous layout of this mmr) - // this should not happen since the elements are linked? - for (Element* e : s->annotations()) { - // look at elements in mmr - if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() - || e->isInstrumentChange())) { - continue; - } - // try to find a match in underlying measure - bool found = false; - for (Element* ee : underlyingSeg->annotations()) { - if (e->linkList().contains(ee)) { - found = true; - break; - } - } - // remove from mmr if no match found - if (!found) { - undo(new RemoveElement(e)); - } - } - } - - MeasureBase* nm = _showVBox ? lastMeasure->next() : lastMeasure->nextMeasure(); - mmrMeasure->setNext(nm); - mmrMeasure->setPrev(firstMeasure->prev()); -} - -//--------------------------------------------------------- -// doLayout -// do a complete (re-) layout -//--------------------------------------------------------- - -void Score::doLayout() -{ - doLayoutRange(Fraction(0, 1), Fraction(-1, 1)); -} - -void Score::doLayoutRange(const Fraction& st, const Fraction& et) -{ - m_layout.doLayoutRange(st, et); -} -} diff --git a/src/engraving/libmscore/layout.h b/src/engraving/libmscore/layout.h deleted file mode 100644 index 046872d0ac..0000000000 --- a/src/engraving/libmscore/layout.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) 2021 MuseScore BVBA and others - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __LAYOUT_H__ -#define __LAYOUT_H__ - -#endif diff --git a/src/engraving/libmscore/layout/layout.cpp b/src/engraving/libmscore/layout/layout.cpp index 025e261b34..6979e5b9e5 100644 --- a/src/engraving/libmscore/layout/layout.cpp +++ b/src/engraving/libmscore/layout/layout.cpp @@ -42,8 +42,8 @@ #include "../stafflines.h" #include "../tuplet.h" #include "../tie.h" -#include "../layout.h" +#include "layoutcontext.h" #include "layoutmeasure.h" using namespace mu::engraving; @@ -71,175 +71,6 @@ static bool inline almostZero(qreal value) return value > -1e-3 && value < 1e-3; } -//--------------------------------------------------------- -// validMMRestMeasure -// return true if this might be a measure in a -// multi measure rest -//--------------------------------------------------------- - -static bool validMMRestMeasure(Measure* m) -{ - if (m->irregular()) { - return false; - } - - int n = 0; - for (Segment* s = m->first(); s; s = s->next()) { - for (Element* e : s->annotations()) { - if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() - || e->isInstrumentChange())) { - return false; - } - } - if (s->isChordRestType()) { - bool restFound = false; - int tracks = m->score()->ntracks(); - for (int track = 0; track < tracks; ++track) { - if ((track % VOICES) == 0 && !m->score()->staff(track / VOICES)->show()) { - track += VOICES - 1; - continue; - } - if (s->element(track)) { - if (!s->element(track)->isRest()) { - return false; - } - restFound = true; - } - } - for (Element* e : s->annotations()) { - if (e->isFermata()) { - return false; - } - } - if (restFound) { - ++n; - } - // measure is not empty if there is more than one rest - if (n > 1) { - return false; - } - } - } - return true; -} - -//--------------------------------------------------------- -// breakMultiMeasureRest -// return true if this measure should start a new -// multi measure rest -//--------------------------------------------------------- - -static bool breakMultiMeasureRest(Measure* m) -{ - if (m->breakMultiMeasureRest()) { - return true; - } - - if (m->repeatStart() - || (m->prevMeasure() && m->prevMeasure()->repeatEnd()) - || (m->isIrregular()) - || (m->prevMeasure() && m->prevMeasure()->isIrregular()) - || (m->prevMeasure() && (m->prevMeasure()->sectionBreak()))) { - return true; - } - - auto sl = m->score()->spannerMap().findOverlapping(m->tick().ticks(), m->endTick().ticks()); - for (auto i : sl) { - Spanner* s = i.value; - // break for first measure of volta or textline and first measure *after* volta - if ((s->isVolta() || s->isTextLine()) && (s->tick() == m->tick() || s->tick2() == m->tick())) { - return true; - } - } - - // break for marker in this measure - for (Element* e : m->el()) { - if (e->isMarker()) { - Marker* mark = toMarker(e); - if (!(mark->align() & Align::RIGHT)) { - return true; - } - } - } - - // break for marker & jump in previous measure - Measure* pm = m->prevMeasure(); - if (pm) { - for (Element* e : pm->el()) { - if (e->isJump()) { - return true; - } else if (e->isMarker()) { - Marker* mark = toMarker(e); - if (mark->align() & Align::RIGHT) { - return true; - } - } - } - } - - // break for MeasureRepeat group - for (int staffIdx = 0; staffIdx < m->score()->nstaves(); ++staffIdx) { - if (m->isMeasureRepeatGroup(staffIdx) - || (m->prevMeasure() && m->prevMeasure()->isMeasureRepeatGroup(staffIdx))) { - return true; - } - } - - for (Segment* s = m->first(); s; s = s->next()) { - for (Element* e : s->annotations()) { - if (!e->visible()) { - continue; - } - if (e->isRehearsalMark() - || e->isTempoText() - || ((e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()) - && (e->systemFlag() || m->score()->staff(e->staffIdx())->show()))) { - return true; - } - } - for (int staffIdx = 0; staffIdx < m->score()->nstaves(); ++staffIdx) { - if (!m->score()->staff(staffIdx)->show()) { - continue; - } - Element* e = s->element(staffIdx * VOICES); - if (!e || e->generated()) { - continue; - } - if (s->isStartRepeatBarLineType()) { - return true; - } - if (s->isType(SegmentType::KeySig | SegmentType::TimeSig) && m->tick().isNotZero()) { - return true; - } - if (s->isClefType()) { - if (s->tick() != m->endTick() && m->tick().isNotZero()) { - return true; - } - } - } - } - if (pm) { - Segment* s = pm->findSegmentR(SegmentType::EndBarLine, pm->ticks()); - if (s) { - for (int staffIdx = 0; staffIdx < s->score()->nstaves(); ++staffIdx) { - BarLine* bl = toBarLine(s->element(staffIdx * VOICES)); - if (bl) { - BarLineType t = bl->barLineType(); - if (t != BarLineType::NORMAL && t != BarLineType::BROKEN && t != BarLineType::DOTTED && !bl->generated()) { - return true; - } else { - break; - } - } - } - } - if (pm->findSegment(SegmentType::Clef, m->tick())) { - return true; - } - } - return false; -} - Layout::Layout(Ms::Score* score) : m_score(score) { @@ -566,28 +397,6 @@ void Layout::collectLinearSystem(LayoutContext& lc) system->setWidth(pos.x()); } -//--------------------------------------------------------- -// layoutDrumsetChord -//--------------------------------------------------------- - -static void layoutDrumsetChord(Chord* c, const Drumset* drumset, const StaffType* st, qreal spatium) -{ - for (Note* note : c->notes()) { - int pitch = note->pitch(); - if (!drumset->isValid(pitch)) { - // qDebug("unmapped drum note %d", pitch); - } else if (!note->fixed()) { - note->undoChangeProperty(Pid::HEAD_GROUP, int(drumset->noteHead(pitch))); - int line = drumset->line(pitch); - note->setLine(line); - - int off = st->stepOffset(); - qreal ld = st->lineDistance().val(); - note->rypos() = (line + off * 2.0) * spatium * .5 * ld; - } - } -} - //--------------------------------------------------------- // extendedStemLenWithTwoNotesTremolo // Goal: To extend stem of one of the chords to make the tremolo less steep @@ -642,298 +451,3 @@ std::pair Layout::extendedStemLenWithTwoNoteTremolo(Tremolo* tremo return { stemLen1, stemLen2 }; } - -//--------------------------------------------------------- -// processLines -//--------------------------------------------------------- - -static void processLines(System* system, std::vector lines, bool align) -{ - std::vector segments; - for (Spanner* sp : lines) { - SpannerSegment* ss = sp->layoutSystem(system); // create/layout spanner segment for this system - if (ss->autoplace()) { - segments.push_back(ss); - } - } - - if (align && segments.size() > 1) { - const int nstaves = system->staves()->size(); - constexpr qreal minY = -1000000.0; - const qreal defaultY = segments[0]->rypos(); - std::vector y(nstaves, minY); - - for (SpannerSegment* ss : segments) { - if (ss->visible()) { - qreal& staffY = y[ss->staffIdx()]; - staffY = qMax(staffY, ss->rypos()); - } - } - for (SpannerSegment* ss : segments) { - if (!ss->isStyled(Pid::OFFSET)) { - continue; - } - const qreal staffY = y[ss->staffIdx()]; - if (staffY > minY) { - ss->rypos() = staffY; - } else { - ss->rypos() = defaultY; - } - } - } - - // - // add shapes to skyline - // - for (SpannerSegment* ss : segments) { - if (ss->addToSkyline()) { - system->staff(ss->staffIdx())->skyline().add(ss->shape().translated(ss->pos())); - } - } -} - -//--------------------------------------------------------- -// isTopTuplet -// returns true for the first CR of a tuplet that is not cross-staff -//--------------------------------------------------------- - -static bool isTopTuplet(ChordRest* cr) -{ - Tuplet* t = cr->tuplet(); - if (t && t->elements().front() == cr) { - // find top level tuplet - while (t->tuplet()) { - t = t->tuplet(); - } - // consider tuplet cross if anything moved within it - if (t->cross()) { - return false; - } else { - return true; - } - } - - // no tuplet or not first element - return false; -} - -//--------------------------------------------------------- -// layoutTies -//--------------------------------------------------------- - -static void layoutTies(Chord* ch, System* system, const Fraction& stick) -{ - SysStaff* staff = system->staff(ch->staffIdx()); - if (!staff->show()) { - return; - } - for (Note* note : ch->notes()) { - Tie* t = note->tieFor(); - if (t) { - TieSegment* ts = t->layoutFor(system); - if (ts && ts->addToSkyline()) { - staff->skyline().add(ts->shape().translated(ts->pos())); - } - } - t = note->tieBack(); - if (t) { - if (t->startNote()->tick() < stick) { - TieSegment* ts = t->layoutBack(system); - if (ts && ts->addToSkyline()) { - staff->skyline().add(ts->shape().translated(ts->pos())); - } - } - } - } -} - -//--------------------------------------------------------- -// layoutHarmonies -//--------------------------------------------------------- - -static void layoutHarmonies(const std::vector& sl) -{ - for (const Segment* s : sl) { - for (Element* e : s->annotations()) { - if (e->isHarmony()) { - Harmony* h = toHarmony(e); - // For chord symbols that coincide with a chord or rest, - // a partial layout can also happen (if needed) during ChordRest layout - // in order to calculate a bbox and allocate its shape to the ChordRest. - // But that layout (if it happens at all) does not do autoplace, - // so we need the full layout here. - h->layout(); - h->autoplaceSegmentElement(); - } - } - } -} - -//--------------------------------------------------------- -// alignHarmonies -//--------------------------------------------------------- - -static void alignHarmonies(const System* system, const std::vector& sl, bool harmony, const qreal maxShiftAbove, - const qreal maxShiftBelow) -{ - // Help class. - // Contains harmonies/fretboard per segment. - class HarmonyList : public QList - { - QMap > elements; - QList modified; - - Element* getReferenceElement(const Segment* s, bool above, bool visible) const - { - // Returns the reference element for aligning. - // When a segments contains multiple harmonies/fretboard, the lowest placed - // element (for placement above, otherwise the highest placed element) is - // used for alignment. - Element* element { nullptr }; - for (Element* e : elements[s]) { - // Only chord symbols have styled offset, fretboards don't. - if (!e->autoplace() || (e->isHarmony() && !e->isStyled(Pid::OFFSET)) || (visible && !e->visible())) { - continue; - } - if (!element) { - element = e; - } else { - if ((e->placeAbove() && above && (element->y() < e->y())) - || (e->placeBelow() && !above && (element->y() > e->y()))) { - element = e; - } - } - } - return element; - } - - public: - HarmonyList() - { - elements.clear(); - modified.clear(); - } - - void append(const Segment* s, Element* e) - { - elements[s].append(e); - } - - qreal getReferenceHeight(bool above) const - { - // The reference height is the height of - // the lowest element if placed above - // or - // the highest element if placed below. - bool first { true }; - qreal ref { 0.0 }; - for (auto s : elements.keys()) { - Element* e { getReferenceElement(s, above, true) }; - if (!e) { - continue; - } - if (e->placeAbove() && above) { - ref = first ? e->y() : qMin(ref, e->y()); - first = false; - } else if (e->placeBelow() && !above) { - ref = first ? e->y() : qMax(ref, e->y()); - first = false; - } - } - return ref; - } - - bool align(bool above, qreal reference, qreal maxShift) - { - // Align the elements. If a segment contains multiple elements, - // only the reference elements is used in the algorithm. All other - // elements will remain their original placement with respect to - // the reference element. - bool moved { false }; - if (almostZero(reference)) { - return moved; - } - - for (auto s : elements.keys()) { - QList handled; - Element* be = getReferenceElement(s, above, false); - if (!be) { - // If there are only invisible elements, we have to use an invisible - // element for alignment reference. - be = getReferenceElement(s, above, true); - } - if (be && ((above && (be->y() < (reference + maxShift))) || ((!above && (be->y() > (reference - maxShift)))))) { - qreal shift = be->rypos(); - be->rypos() = reference - be->ryoffset(); - shift -= be->rypos(); - for (Element* e : elements[s]) { - if ((above && e->placeBelow()) || (!above && e->placeAbove())) { - continue; - } - modified.append(e); - handled.append(e); - moved = true; - if (e != be) { - e->rypos() -= shift; - } - } - for (auto e : handled) { - elements[s].removeOne(e); - } - } - } - return moved; - } - - void addToSkyline(const System* system) - { - for (Element* e : qAsConst(modified)) { - const Segment* s = toSegment(e->parent()); - const MeasureBase* m = toMeasureBase(s->parent()); - system->staff(e->staffIdx())->skyline().add(e->shape().translated(e->pos() + s->pos() + m->pos())); - if (e->isFretDiagram()) { - FretDiagram* fd = toFretDiagram(e); - Harmony* h = fd->harmony(); - if (h) { - system->staff(e->staffIdx())->skyline().add(h->shape().translated(h->pos() + fd->pos() + s->pos() + m->pos())); - } else { - system->staff(e->staffIdx())->skyline().add(fd->shape().translated(fd->pos() + s->pos() + m->pos())); - } - } - } - } - }; - - if (almostZero(maxShiftAbove) && almostZero(maxShiftBelow)) { - return; - } - - // Collect all fret diagrams and chord symbol and store them per staff. - // In the same pass, the maximum height is collected. - QMap staves; - for (const Segment* s : sl) { - for (Element* e : s->annotations()) { - if ((harmony && e->isHarmony()) || (!harmony && e->isFretDiagram())) { - staves[e->staffIdx()].append(s, e); - } - } - } - - for (int idx: staves.keys()) { - // Align the objects. - // Algorithm: - // - Find highest placed harmony/fretdiagram. - // - Align all harmony/fretdiagram objects placed between height and height-maxShiftAbove. - // - Repeat for all harmony/fretdiagram objects below heigt-maxShiftAbove. - bool moved { true }; - int pass { 0 }; - while (moved && (pass++ < 10)) { - moved = false; - moved |= staves[idx].align(true, staves[idx].getReferenceHeight(true), maxShiftAbove); - moved |= staves[idx].align(false, staves[idx].getReferenceHeight(false), maxShiftBelow); - } - - // Add all aligned objects to the sky line. - staves[idx].addToSkyline(system); - } -} diff --git a/src/engraving/libmscore/layout/layout.h b/src/engraving/libmscore/layout/layout.h index 48668f55c7..6c6984daa4 100644 --- a/src/engraving/libmscore/layout/layout.h +++ b/src/engraving/libmscore/layout/layout.h @@ -22,16 +22,15 @@ #ifndef MU_ENGRAVING_LAYOUT_H #define MU_ENGRAVING_LAYOUT_H -#include "../fraction.h" -#include "../score.h" - -#include "layoutcontext.h" - namespace Ms { +class Score; +class Fraction; +class System; class Tremolo; } namespace mu::engraving { +class LayoutContext; class Layout { public: diff --git a/src/engraving/libmscore/layout/layoutbeams.cpp b/src/engraving/libmscore/layout/layoutbeams.cpp index 82c95ed942..c5595e71d7 100644 --- a/src/engraving/libmscore/layout/layoutbeams.cpp +++ b/src/engraving/libmscore/layout/layoutbeams.cpp @@ -24,6 +24,7 @@ #include "../score.h" #include "../staff.h" #include "../chord.h" +#include "../timesig.h" #include "layoutcontext.h" diff --git a/src/engraving/libmscore/layout/layoutchords.cpp b/src/engraving/libmscore/layout/layoutchords.cpp index 7327dbbba5..094e18e8f8 100644 --- a/src/engraving/libmscore/layout/layoutchords.cpp +++ b/src/engraving/libmscore/layout/layoutchords.cpp @@ -29,6 +29,7 @@ #include "../chord.h" #include "../stemslash.h" #include "../hook.h" +#include "../accidental.h" using namespace mu::engraving; using namespace Ms; diff --git a/src/engraving/libmscore/layout/layoutcontext.cpp b/src/engraving/libmscore/layout/layoutcontext.cpp index 6ab96366b0..78f01b28fa 100644 --- a/src/engraving/libmscore/layout/layoutcontext.cpp +++ b/src/engraving/libmscore/layout/layoutcontext.cpp @@ -21,10 +21,30 @@ */ #include "layoutcontext.h" +#include "realfn.h" + #include "../spacer.h" #include "../systemdivider.h" #include "../measure.h" #include "../system.h" +#include "../volta.h" +#include "../staff.h" +#include "../chordrest.h" +#include "../mmrestrange.h" +#include "../chord.h" +#include "../fingering.h" +#include "../barline.h" +#include "../tremolo.h" +#include "../measurenumber.h" +#include "../stafflines.h" +#include "../tuplet.h" +#include "../tie.h" +#include "../dynamic.h" +#include "../harmony.h" +#include "../fret.h" +#include "../bracketItem.h" +#include "../box.h" +#include "../part.h" #include "layout.h" #include "layoutlyrics.h" @@ -33,6 +53,7 @@ #include "layouttuplets.h" #include "verticalgapdata.h" +using namespace mu; using namespace mu::engraving; using namespace Ms; @@ -95,6 +116,276 @@ void LayoutContext::layout() score->systems().append(systemList); // TODO } +//--------------------------------------------------------- +// processLines +//--------------------------------------------------------- + +static void processLines(System* system, std::vector lines, bool align) +{ + std::vector segments; + for (Spanner* sp : lines) { + SpannerSegment* ss = sp->layoutSystem(system); // create/layout spanner segment for this system + if (ss->autoplace()) { + segments.push_back(ss); + } + } + + if (align && segments.size() > 1) { + const int nstaves = system->staves()->size(); + constexpr qreal minY = -1000000.0; + const qreal defaultY = segments[0]->rypos(); + std::vector y(nstaves, minY); + + for (SpannerSegment* ss : segments) { + if (ss->visible()) { + qreal& staffY = y[ss->staffIdx()]; + staffY = qMax(staffY, ss->rypos()); + } + } + for (SpannerSegment* ss : segments) { + if (!ss->isStyled(Pid::OFFSET)) { + continue; + } + const qreal staffY = y[ss->staffIdx()]; + if (staffY > minY) { + ss->rypos() = staffY; + } else { + ss->rypos() = defaultY; + } + } + } + + // + // add shapes to skyline + // + for (SpannerSegment* ss : segments) { + if (ss->addToSkyline()) { + system->staff(ss->staffIdx())->skyline().add(ss->shape().translated(ss->pos())); + } + } +} + +//--------------------------------------------------------- +// layoutTies +//--------------------------------------------------------- + +static void layoutTies(Chord* ch, System* system, const Fraction& stick) +{ + SysStaff* staff = system->staff(ch->staffIdx()); + if (!staff->show()) { + return; + } + for (Note* note : ch->notes()) { + Tie* t = note->tieFor(); + if (t) { + TieSegment* ts = t->layoutFor(system); + if (ts && ts->addToSkyline()) { + staff->skyline().add(ts->shape().translated(ts->pos())); + } + } + t = note->tieBack(); + if (t) { + if (t->startNote()->tick() < stick) { + TieSegment* ts = t->layoutBack(system); + if (ts && ts->addToSkyline()) { + staff->skyline().add(ts->shape().translated(ts->pos())); + } + } + } + } +} + +//--------------------------------------------------------- +// layoutHarmonies +//--------------------------------------------------------- + +static void layoutHarmonies(const std::vector& sl) +{ + for (const Segment* s : sl) { + for (Element* e : s->annotations()) { + if (e->isHarmony()) { + Harmony* h = toHarmony(e); + // For chord symbols that coincide with a chord or rest, + // a partial layout can also happen (if needed) during ChordRest layout + // in order to calculate a bbox and allocate its shape to the ChordRest. + // But that layout (if it happens at all) does not do autoplace, + // so we need the full layout here. + h->layout(); + h->autoplaceSegmentElement(); + } + } + } +} + +//--------------------------------------------------------- +// alignHarmonies +//--------------------------------------------------------- + +static void alignHarmonies(const System* system, const std::vector& sl, bool harmony, const qreal maxShiftAbove, + const qreal maxShiftBelow) +{ + // Help class. + // Contains harmonies/fretboard per segment. + class HarmonyList : public QList + { + QMap > elements; + QList modified; + + Element* getReferenceElement(const Segment* s, bool above, bool visible) const + { + // Returns the reference element for aligning. + // When a segments contains multiple harmonies/fretboard, the lowest placed + // element (for placement above, otherwise the highest placed element) is + // used for alignment. + Element* element { nullptr }; + for (Element* e : elements[s]) { + // Only chord symbols have styled offset, fretboards don't. + if (!e->autoplace() || (e->isHarmony() && !e->isStyled(Pid::OFFSET)) || (visible && !e->visible())) { + continue; + } + if (!element) { + element = e; + } else { + if ((e->placeAbove() && above && (element->y() < e->y())) + || (e->placeBelow() && !above && (element->y() > e->y()))) { + element = e; + } + } + } + return element; + } + + public: + HarmonyList() + { + elements.clear(); + modified.clear(); + } + + void append(const Segment* s, Element* e) + { + elements[s].append(e); + } + + qreal getReferenceHeight(bool above) const + { + // The reference height is the height of + // the lowest element if placed above + // or + // the highest element if placed below. + bool first { true }; + qreal ref { 0.0 }; + for (auto s : elements.keys()) { + Element* e { getReferenceElement(s, above, true) }; + if (!e) { + continue; + } + if (e->placeAbove() && above) { + ref = first ? e->y() : qMin(ref, e->y()); + first = false; + } else if (e->placeBelow() && !above) { + ref = first ? e->y() : qMax(ref, e->y()); + first = false; + } + } + return ref; + } + + bool align(bool above, qreal reference, qreal maxShift) + { + // Align the elements. If a segment contains multiple elements, + // only the reference elements is used in the algorithm. All other + // elements will remain their original placement with respect to + // the reference element. + bool moved { false }; + if (mu::RealIsNull(reference)) { + return moved; + } + + for (auto s : elements.keys()) { + QList handled; + Element* be = getReferenceElement(s, above, false); + if (!be) { + // If there are only invisible elements, we have to use an invisible + // element for alignment reference. + be = getReferenceElement(s, above, true); + } + if (be && ((above && (be->y() < (reference + maxShift))) || ((!above && (be->y() > (reference - maxShift)))))) { + qreal shift = be->rypos(); + be->rypos() = reference - be->ryoffset(); + shift -= be->rypos(); + for (Element* e : elements[s]) { + if ((above && e->placeBelow()) || (!above && e->placeAbove())) { + continue; + } + modified.append(e); + handled.append(e); + moved = true; + if (e != be) { + e->rypos() -= shift; + } + } + for (auto e : handled) { + elements[s].removeOne(e); + } + } + } + return moved; + } + + void addToSkyline(const System* system) + { + for (Element* e : qAsConst(modified)) { + const Segment* s = toSegment(e->parent()); + const MeasureBase* m = toMeasureBase(s->parent()); + system->staff(e->staffIdx())->skyline().add(e->shape().translated(e->pos() + s->pos() + m->pos())); + if (e->isFretDiagram()) { + FretDiagram* fd = toFretDiagram(e); + Harmony* h = fd->harmony(); + if (h) { + system->staff(e->staffIdx())->skyline().add(h->shape().translated(h->pos() + fd->pos() + s->pos() + m->pos())); + } else { + system->staff(e->staffIdx())->skyline().add(fd->shape().translated(fd->pos() + s->pos() + m->pos())); + } + } + } + } + }; + + if (RealIsNull(maxShiftAbove) && RealIsNull(maxShiftBelow)) { + return; + } + + // Collect all fret diagrams and chord symbol and store them per staff. + // In the same pass, the maximum height is collected. + QMap staves; + for (const Segment* s : sl) { + for (Element* e : s->annotations()) { + if ((harmony && e->isHarmony()) || (!harmony && e->isFretDiagram())) { + staves[e->staffIdx()].append(s, e); + } + } + } + + for (int idx: staves.keys()) { + // Align the objects. + // Algorithm: + // - Find highest placed harmony/fretdiagram. + // - Align all harmony/fretdiagram objects placed between height and height-maxShiftAbove. + // - Repeat for all harmony/fretdiagram objects below heigt-maxShiftAbove. + bool moved { true }; + int pass { 0 }; + while (moved && (pass++ < 10)) { + moved = false; + moved |= staves[idx].align(true, staves[idx].getReferenceHeight(true), maxShiftAbove); + moved |= staves[idx].align(false, staves[idx].getReferenceHeight(false), maxShiftBelow); + } + + // Add all aligned objects to the sky line. + staves[idx].addToSkyline(system); + } +} + //--------------------------------------------------------- // layoutSystemElements //--------------------------------------------------------- @@ -343,7 +634,7 @@ void LayoutContext::layoutSystemElements(System* system) continue; } ChordRest* cr = toChordRest(e); - if (!isTopTuplet(cr)) { + if (!LayoutTuplets::isTopTuplet(cr)) { continue; } DurationElement* de = cr; @@ -908,11 +1199,11 @@ static void distributeStaves(Page* page) // Try to make the gaps equal, taking the spread factors and maximum spacing into account. static const int maxPasses { 20 }; // Saveguard to prevent endless loops. int pass { 0 }; - while (!almostZero(spaceLeft) && (ngaps > 0) && (++pass < maxPasses)) { + while (!RealIsNull(spaceLeft) && (ngaps > 0) && (++pass < maxPasses)) { ngaps = 0; qreal smallest { vgdl.smallest() }; qreal nextSmallest { vgdl.smallest(smallest) }; - if (almostZero(smallest) || almostZero(nextSmallest)) { + if (RealIsNull(smallest) || RealIsNull(nextSmallest)) { break; } @@ -923,7 +1214,7 @@ static void distributeStaves(Page* page) qreal addedSpace { 0.0 }; VerticalGapDataList modified; for (VerticalGapData* vgd : vgdl) { - if (!almostZero(vgd->spacing() - smallest)) { + if (!RealIsNull(vgd->spacing() - smallest)) { continue; } qreal step { nextSmallest - vgd->spacing() }; @@ -931,7 +1222,7 @@ static void distributeStaves(Page* page) continue; } step = vgd->addSpacing(step); - if (!almostZero(step)) { + if (!RealIsNull(step)) { addedSpace += step * vgd->factor(); modified.append(vgd); ++ngaps; @@ -956,13 +1247,13 @@ static void distributeStaves(Page* page) spaceLeft = qMin(maxPageFill * vgdl.length(), spaceLeft); pass = 0; ngaps = 1; - while (!almostZero(spaceLeft) && !almostZero(maxPageFill) && (ngaps > 0) && (++pass < maxPasses)) { + while (!RealIsNull(spaceLeft) && !RealIsNull(maxPageFill) && (ngaps > 0) && (++pass < maxPasses)) { ngaps = 0; qreal addedSpace { 0.0 }; qreal step { spaceLeft / vgdl.sumStretchFactor() }; for (VerticalGapData* vgd : vgdl) { qreal res { vgd->addFillSpacing(step, maxPageFill) }; - if (!almostZero(res)) { + if (!RealIsNull(res)) { addedSpace += res * vgd->factor(); ++ngaps; } diff --git a/src/engraving/libmscore/layout/layoutmeasure.cpp b/src/engraving/libmscore/layout/layoutmeasure.cpp index 38bd8a56aa..8878b84a74 100644 --- a/src/engraving/libmscore/layout/layoutmeasure.cpp +++ b/src/engraving/libmscore/layout/layoutmeasure.cpp @@ -23,6 +23,15 @@ #include "../score.h" #include "../measure.h" +#include "../undo.h" +#include "../mmrest.h" +#include "../ambitus.h" +#include "../barline.h" +#include "../keysig.h" +#include "../stem.h" +#include "../lyrics.h" +#include "../marker.h" +#include "../part.h" #include "layout.h" #include "layoutcontext.h" @@ -32,6 +41,537 @@ using namespace mu::engraving; using namespace Ms; +//--------------------------------------------------------- +// createMMRest +// create a multimeasure rest +// from firstMeasure to lastMeasure (inclusive) +//--------------------------------------------------------- + +void LayoutMeasure::createMMRest(Score* score, Measure* firstMeasure, Measure* lastMeasure, const Fraction& len) +{ + int numMeasuresInMMRest = 1; + if (firstMeasure != lastMeasure) { + for (Measure* m = firstMeasure->nextMeasure(); m; m = m->nextMeasure()) { + ++numMeasuresInMMRest; + m->setMMRestCount(-1); + if (m->mmRest()) { + score->undo(new ChangeMMRest(m, 0)); + } + if (m == lastMeasure) { + break; + } + } + } + + // mmrMeasure coexists with n undisplayed measures of rests + Measure* mmrMeasure = firstMeasure->mmRest(); + if (mmrMeasure) { + // reuse existing mmrest + if (mmrMeasure->ticks() != len) { + Segment* s = mmrMeasure->findSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks()); + // adjust length + mmrMeasure->setTicks(len); + // move existing end barline + if (s) { + s->setRtick(len); + } + } + mmrMeasure->removeSystemTrailer(); + } else { + mmrMeasure = new Measure(score); + mmrMeasure->setTicks(len); + mmrMeasure->setTick(firstMeasure->tick()); + score->undo(new ChangeMMRest(firstMeasure, mmrMeasure)); + } + mmrMeasure->setTimesig(firstMeasure->timesig()); + mmrMeasure->setPageBreak(lastMeasure->pageBreak()); + mmrMeasure->setLineBreak(lastMeasure->lineBreak()); + mmrMeasure->setMMRestCount(numMeasuresInMMRest); + mmrMeasure->setNo(firstMeasure->no()); + + // + // set mmrMeasure with same barline as last underlying measure + // + Segment* lastMeasureEndBarlineSeg = lastMeasure->findSegmentR(SegmentType::EndBarLine, lastMeasure->ticks()); + if (lastMeasureEndBarlineSeg) { + Segment* mmrEndBarlineSeg = mmrMeasure->undoGetSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks()); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + Element* e = lastMeasureEndBarlineSeg->element(staffIdx * VOICES); + if (e) { + bool generated = e->generated(); + if (!mmrEndBarlineSeg->element(staffIdx * VOICES)) { + Element* eClone = generated ? e->clone() : e->linkedClone(); + eClone->setGenerated(generated); + eClone->setParent(mmrEndBarlineSeg); + score->undoAddElement(eClone); + } else { + BarLine* mmrEndBarline = toBarLine(mmrEndBarlineSeg->element(staffIdx * VOICES)); + BarLine* lastMeasureEndBarline = toBarLine(e); + if (!generated && !mmrEndBarline->links()) { + score->undo(new Link(mmrEndBarline, lastMeasureEndBarline)); + } + if (mmrEndBarline->barLineType() != lastMeasureEndBarline->barLineType()) { + // change directly when generating mmrests, do not change underlying measures or follow links + score->undo(new ChangeProperty(mmrEndBarline, Pid::BARLINE_TYPE, + QVariant::fromValue(lastMeasureEndBarline->barLineType()), + PropertyFlags::NOSTYLE)); + score->undo(new ChangeProperty(mmrEndBarline, Pid::GENERATED, generated, PropertyFlags::NOSTYLE)); + } + } + } + } + } + + // + // if last underlying measure ends with clef change, show same at end of mmrest + // + Segment* lastMeasureClefSeg = lastMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, + lastMeasure->ticks()); + if (lastMeasureClefSeg) { + Segment* mmrClefSeg = mmrMeasure->undoGetSegment(lastMeasureClefSeg->segmentType(), lastMeasure->endTick()); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + const int track = staff2track(staffIdx); + Element* e = lastMeasureClefSeg->element(track); + if (e && e->isClef()) { + Clef* lastMeasureClef = toClef(e); + if (!mmrClefSeg->element(track)) { + Clef* mmrClef = lastMeasureClef->generated() ? lastMeasureClef->clone() : toClef( + lastMeasureClef->linkedClone()); + mmrClef->setParent(mmrClefSeg); + score->undoAddElement(mmrClef); + } else { + Clef* mmrClef = toClef(mmrClefSeg->element(track)); + mmrClef->setClefType(lastMeasureClef->clefType()); + mmrClef->setShowCourtesy(lastMeasureClef->showCourtesy()); + } + } + } + } + + mmrMeasure->setRepeatStart(firstMeasure->repeatStart() || lastMeasure->repeatStart()); + mmrMeasure->setRepeatEnd(firstMeasure->repeatEnd() || lastMeasure->repeatEnd()); + mmrMeasure->setSectionBreak(lastMeasure->sectionBreak()); + + // + // copy markers to mmrMeasure + // + ElementList oldList = mmrMeasure->takeElements(); + ElementList newList = lastMeasure->el(); + for (Element* e : firstMeasure->el()) { + if (e->isMarker()) { + newList.push_back(e); + } + } + for (Element* e : newList) { + bool found = false; + for (Element* ee : oldList) { + if (ee->type() == e->type() && ee->subtype() == e->subtype()) { + mmrMeasure->add(ee); + auto i = std::find(oldList.begin(), oldList.end(), ee); + if (i != oldList.end()) { + oldList.erase(i); + } + found = true; + break; + } + } + if (!found) { + mmrMeasure->add(e->clone()); + } + } + for (Element* e : oldList) { + delete e; + } + Segment* s = mmrMeasure->undoGetSegmentR(SegmentType::ChordRest, Fraction(0, 1)); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + int track = staffIdx * VOICES; + if (s->element(track) == 0) { + MMRest* mmr = new MMRest(score); + mmr->setDurationType(TDuration::DurationType::V_MEASURE); + mmr->setTicks(mmrMeasure->ticks()); + mmr->setTrack(track); + mmr->setParent(s); + score->undo(new AddElement(mmr)); + } + } + + // + // further check for clefs + // + Segment* underlyingSeg = lastMeasure->findSegmentR(SegmentType::Clef, lastMeasure->ticks()); + Segment* mmrSeg = mmrMeasure->findSegment(SegmentType::Clef, lastMeasure->endTick()); + if (underlyingSeg) { + if (mmrSeg == 0) { + mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::Clef, lastMeasure->ticks()); + } + mmrSeg->setEnabled(underlyingSeg->enabled()); + mmrSeg->setTrailer(underlyingSeg->trailer()); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + int track = staffIdx * VOICES; + Clef* clef = toClef(underlyingSeg->element(track)); + if (clef) { + if (mmrSeg->element(track) == 0) { + mmrSeg->add(clef->clone()); + } else { + //TODO: check if same clef + } + } + } + } else if (mmrSeg) { + // TODO: remove elements from mmrSeg? + score->undo(new RemoveElement(mmrSeg)); + } + + // + // check for time signature + // + underlyingSeg = firstMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1)); + mmrSeg = mmrMeasure->findSegment(SegmentType::TimeSig, firstMeasure->tick()); + if (underlyingSeg) { + if (mmrSeg == 0) { + mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1)); + } + mmrSeg->setEnabled(underlyingSeg->enabled()); + mmrSeg->setHeader(underlyingSeg->header()); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + int track = staffIdx * VOICES; + TimeSig* underlyingTimeSig = toTimeSig(underlyingSeg->element(track)); + if (underlyingTimeSig) { + TimeSig* mmrTimeSig = toTimeSig(mmrSeg->element(track)); + if (!mmrTimeSig) { + mmrTimeSig = underlyingTimeSig->generated() ? underlyingTimeSig->clone() : toTimeSig( + underlyingTimeSig->linkedClone()); + mmrTimeSig->setParent(mmrSeg); + score->undo(new AddElement(mmrTimeSig)); + } else { + mmrTimeSig->setSig(underlyingTimeSig->sig(), underlyingTimeSig->timeSigType()); + mmrTimeSig->layout(); + } + } + } + } else if (mmrSeg) { + // TODO: remove elements from mmrSeg? + score->undo(new RemoveElement(mmrSeg)); + } + + // + // check for ambitus + // + underlyingSeg = firstMeasure->findSegmentR(SegmentType::Ambitus, Fraction(0, 1)); + mmrSeg = mmrMeasure->findSegment(SegmentType::Ambitus, firstMeasure->tick()); + if (underlyingSeg) { + if (mmrSeg == 0) { + mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::Ambitus, Fraction(0, 1)); + } + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + int track = staffIdx * VOICES; + Ambitus* underlyingAmbitus = toAmbitus(underlyingSeg->element(track)); + if (underlyingAmbitus) { + Ambitus* mmrAmbitus = toAmbitus(mmrSeg->element(track)); + if (!mmrAmbitus) { + mmrAmbitus = underlyingAmbitus->clone(); + mmrAmbitus->setParent(mmrSeg); + score->undo(new AddElement(mmrAmbitus)); + } else { + mmrAmbitus->initFrom(underlyingAmbitus); + mmrAmbitus->layout(); + } + } + } + } else if (mmrSeg) { + // TODO: remove elements from mmrSeg? + score->undo(new RemoveElement(mmrSeg)); + } + + // + // check for key signature + // + underlyingSeg = firstMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1)); + mmrSeg = mmrMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1)); + if (underlyingSeg) { + if (mmrSeg == 0) { + mmrSeg = mmrMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1)); + } + mmrSeg->setEnabled(underlyingSeg->enabled()); + mmrSeg->setHeader(underlyingSeg->header()); + for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) { + int track = staffIdx * VOICES; + KeySig* underlyingKeySig = toKeySig(underlyingSeg->element(track)); + if (underlyingKeySig) { + KeySig* mmrKeySig = toKeySig(mmrSeg->element(track)); + if (!mmrKeySig) { + mmrKeySig = underlyingKeySig->generated() ? underlyingKeySig->clone() : toKeySig( + underlyingKeySig->linkedClone()); + mmrKeySig->setParent(mmrSeg); + mmrKeySig->setGenerated(true); + score->undo(new AddElement(mmrKeySig)); + } else { + if (!(mmrKeySig->keySigEvent() == underlyingKeySig->keySigEvent())) { + bool addKey = underlyingKeySig->isChange(); + score->undo(new ChangeKeySig(mmrKeySig, underlyingKeySig->keySigEvent(), mmrKeySig->showCourtesy(), + addKey)); + } + } + } + } + } else if (mmrSeg) { + mmrSeg->setEnabled(false); + // TODO: remove elements from mmrSeg, then delete mmrSeg + // previously we removed the segment if not empty, + // but this resulted in "stale" keysig in mmrest after removed from underlying measure + //undo(new RemoveElement(mmrSeg)); + } + + mmrMeasure->checkHeader(); + mmrMeasure->checkTrailer(); + + // + // check for rehearsal mark etc. + // + underlyingSeg = firstMeasure->findSegmentR(SegmentType::ChordRest, Fraction(0, 1)); + if (underlyingSeg) { + // clone elements from underlying measure to mmr + for (Element* e : underlyingSeg->annotations()) { + // look at elements in underlying measure + if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() + || e->isInstrumentChange())) { + continue; + } + // try to find a match in mmr + bool found = false; + for (Element* ee : s->annotations()) { + if (e->linkList().contains(ee)) { + found = true; + break; + } + } + // add to mmr if no match found + if (!found) { + Element* eClone = e->linkedClone(); + eClone->setParent(s); + score->undo(new AddElement(eClone)); + } + } + + // remove stray elements (possibly leftover from a previous layout of this mmr) + // this should not happen since the elements are linked? + for (Element* e : s->annotations()) { + // look at elements in mmr + if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() + || e->isInstrumentChange())) { + continue; + } + // try to find a match in underlying measure + bool found = false; + for (Element* ee : underlyingSeg->annotations()) { + if (e->linkList().contains(ee)) { + found = true; + break; + } + } + // remove from mmr if no match found + if (!found) { + score->undo(new RemoveElement(e)); + } + } + } + + MeasureBase* nm = score->_showVBox ? lastMeasure->next() : lastMeasure->nextMeasure(); + mmrMeasure->setNext(nm); + mmrMeasure->setPrev(firstMeasure->prev()); +} + +//--------------------------------------------------------- +// validMMRestMeasure +// return true if this might be a measure in a +// multi measure rest +//--------------------------------------------------------- + +static bool validMMRestMeasure(Measure* m) +{ + if (m->irregular()) { + return false; + } + + int n = 0; + for (Segment* s = m->first(); s; s = s->next()) { + for (Element* e : s->annotations()) { + if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() + || e->isInstrumentChange())) { + return false; + } + } + if (s->isChordRestType()) { + bool restFound = false; + int tracks = m->score()->ntracks(); + for (int track = 0; track < tracks; ++track) { + if ((track % VOICES) == 0 && !m->score()->staff(track / VOICES)->show()) { + track += VOICES - 1; + continue; + } + if (s->element(track)) { + if (!s->element(track)->isRest()) { + return false; + } + restFound = true; + } + } + for (Element* e : s->annotations()) { + if (e->isFermata()) { + return false; + } + } + if (restFound) { + ++n; + } + // measure is not empty if there is more than one rest + if (n > 1) { + return false; + } + } + } + return true; +} + +//--------------------------------------------------------- +// breakMultiMeasureRest +// return true if this measure should start a new +// multi measure rest +//--------------------------------------------------------- + +static bool breakMultiMeasureRest(Measure* m) +{ + if (m->breakMultiMeasureRest()) { + return true; + } + + if (m->repeatStart() + || (m->prevMeasure() && m->prevMeasure()->repeatEnd()) + || (m->isIrregular()) + || (m->prevMeasure() && m->prevMeasure()->isIrregular()) + || (m->prevMeasure() && (m->prevMeasure()->sectionBreak()))) { + return true; + } + + auto sl = m->score()->spannerMap().findOverlapping(m->tick().ticks(), m->endTick().ticks()); + for (auto i : sl) { + Spanner* s = i.value; + // break for first measure of volta or textline and first measure *after* volta + if ((s->isVolta() || s->isTextLine()) && (s->tick() == m->tick() || s->tick2() == m->tick())) { + return true; + } + } + + // break for marker in this measure + for (Element* e : m->el()) { + if (e->isMarker()) { + Marker* mark = toMarker(e); + if (!(mark->align() & Align::RIGHT)) { + return true; + } + } + } + + // break for marker & jump in previous measure + Measure* pm = m->prevMeasure(); + if (pm) { + for (Element* e : pm->el()) { + if (e->isJump()) { + return true; + } else if (e->isMarker()) { + Marker* mark = toMarker(e); + if (mark->align() & Align::RIGHT) { + return true; + } + } + } + } + + // break for MeasureRepeat group + for (int staffIdx = 0; staffIdx < m->score()->nstaves(); ++staffIdx) { + if (m->isMeasureRepeatGroup(staffIdx) + || (m->prevMeasure() && m->prevMeasure()->isMeasureRepeatGroup(staffIdx))) { + return true; + } + } + + for (Segment* s = m->first(); s; s = s->next()) { + for (Element* e : s->annotations()) { + if (!e->visible()) { + continue; + } + if (e->isRehearsalMark() + || e->isTempoText() + || ((e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()) + && (e->systemFlag() || m->score()->staff(e->staffIdx())->show()))) { + return true; + } + } + for (int staffIdx = 0; staffIdx < m->score()->nstaves(); ++staffIdx) { + if (!m->score()->staff(staffIdx)->show()) { + continue; + } + Element* e = s->element(staffIdx * VOICES); + if (!e || e->generated()) { + continue; + } + if (s->isStartRepeatBarLineType()) { + return true; + } + if (s->isType(SegmentType::KeySig | SegmentType::TimeSig) && m->tick().isNotZero()) { + return true; + } + if (s->isClefType()) { + if (s->tick() != m->endTick() && m->tick().isNotZero()) { + return true; + } + } + } + } + if (pm) { + Segment* s = pm->findSegmentR(SegmentType::EndBarLine, pm->ticks()); + if (s) { + for (int staffIdx = 0; staffIdx < s->score()->nstaves(); ++staffIdx) { + BarLine* bl = toBarLine(s->element(staffIdx * VOICES)); + if (bl) { + BarLineType t = bl->barLineType(); + if (t != BarLineType::NORMAL && t != BarLineType::BROKEN && t != BarLineType::DOTTED && !bl->generated()) { + return true; + } else { + break; + } + } + } + } + if (pm->findSegment(SegmentType::Clef, m->tick())) { + return true; + } + } + return false; +} + +//--------------------------------------------------------- +// layoutDrumsetChord +//--------------------------------------------------------- + +static void layoutDrumsetChord(Chord* c, const Drumset* drumset, const StaffType* st, qreal spatium) +{ + for (Note* note : c->notes()) { + int pitch = note->pitch(); + if (!drumset->isValid(pitch)) { + // qDebug("unmapped drum note %d", pitch); + } else if (!note->fixed()) { + note->undoChangeProperty(Pid::HEAD_GROUP, int(drumset->noteHead(pitch))); + int line = drumset->line(pitch); + note->setLine(line); + + int off = st->stepOffset(); + qreal ld = st->lineDistance().val(); + note->rypos() = (line + off * 2.0) * spatium * .5 * ld; + } + } +} + void LayoutMeasure::getNextMeasure(Ms::Score* score, LayoutContext& lc) { lc.prevMeasure = lc.curMeasure; @@ -72,7 +612,7 @@ void LayoutMeasure::getNextMeasure(Ms::Score* score, LayoutContext& lc) nm = toMeasure(mb); } if (n >= score->styleI(Sid::minEmptyMeasures)) { - score->createMMRest(m, lm, len); + createMMRest(score, m, lm, len); lc.curMeasure = m->mmRest(); lc.nextMeasure = score->_showVBox ? lm->next() : lm->nextMeasure(); } else { diff --git a/src/engraving/libmscore/layout/layoutmeasure.h b/src/engraving/libmscore/layout/layoutmeasure.h index 7840cb2c9a..096e4ea348 100644 --- a/src/engraving/libmscore/layout/layoutmeasure.h +++ b/src/engraving/libmscore/layout/layoutmeasure.h @@ -24,6 +24,8 @@ namespace Ms { class Score; +class Measure; +class Fraction; } namespace mu::engraving { @@ -34,6 +36,10 @@ public: LayoutMeasure() = default; static void getNextMeasure(Ms::Score* score, LayoutContext& lc); + +private: + + static void createMMRest(Ms::Score* score, Ms::Measure* firstMeasure, Ms::Measure* lastMeasure, const Ms::Fraction& len); }; } diff --git a/src/engraving/libmscore/layout/layouttuplets.cpp b/src/engraving/libmscore/layout/layouttuplets.cpp index 47084f0576..c6252182f9 100644 --- a/src/engraving/libmscore/layout/layouttuplets.cpp +++ b/src/engraving/libmscore/layout/layouttuplets.cpp @@ -27,6 +27,26 @@ using namespace mu::engraving; using namespace Ms; +bool LayoutTuplets::isTopTuplet(ChordRest* cr) +{ + Tuplet* t = cr->tuplet(); + if (t && t->elements().front() == cr) { + // find top level tuplet + while (t->tuplet()) { + t = t->tuplet(); + } + // consider tuplet cross if anything moved within it + if (t->cross()) { + return false; + } else { + return true; + } + } + + // no tuplet or not first element + return false; +} + bool LayoutTuplets::notTopTuplet(ChordRest* cr) { Tuplet* t = cr->tuplet(); diff --git a/src/engraving/libmscore/layout/layouttuplets.h b/src/engraving/libmscore/layout/layouttuplets.h index 553e2d8f9b..28f8691ddc 100644 --- a/src/engraving/libmscore/layout/layouttuplets.h +++ b/src/engraving/libmscore/layout/layouttuplets.h @@ -31,6 +31,7 @@ class LayoutTuplets { public: + static bool isTopTuplet(Ms::ChordRest* cr); static bool notTopTuplet(Ms::ChordRest* cr); }; } diff --git a/src/engraving/libmscore/layoutlinear.cpp b/src/engraving/libmscore/layoutlinear.cpp deleted file mode 100644 index 53881d649f..0000000000 --- a/src/engraving/libmscore/layoutlinear.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) 2021 MuseScore BVBA and others - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "score.h" -#include "page.h" -#include "system.h" -#include "tremolo.h" -#include "measure.h" -#include "layout.h" -#include "bracket.h" -#include "spanner.h" -#include "barline.h" -#include "tie.h" -#include "chord.h" -#include "staff.h" -#include "box.h" -#include "spacer.h" -#include "systemdivider.h" -#include "tuplet.h" -#include "dynamic.h" -#include "stafflines.h" -#include "tempotext.h" -#include "hairpin.h" -#include "part.h" -#include "keysig.h" -#include "sig.h" -#include "breath.h" -#include "tempo.h" -#include "fermata.h" -#include "lyrics.h" - -using namespace mu; - -namespace Ms { -} // namespace Ms diff --git a/src/engraving/libmscore/libmscore.cmake b/src/engraving/libmscore/libmscore.cmake index c67df13521..b4fbdb2850 100644 --- a/src/engraving/libmscore/libmscore.cmake +++ b/src/engraving/libmscore/libmscore.cmake @@ -140,9 +140,6 @@ set(LIBMSCORE_SRC ${CMAKE_CURRENT_LIST_DIR}/lasso.h ${CMAKE_CURRENT_LIST_DIR}/layoutbreak.cpp ${CMAKE_CURRENT_LIST_DIR}/layoutbreak.h - ${CMAKE_CURRENT_LIST_DIR}/layout.cpp - ${CMAKE_CURRENT_LIST_DIR}/layout.h - ${CMAKE_CURRENT_LIST_DIR}/layoutlinear.cpp ${CMAKE_CURRENT_LIST_DIR}/ledgerline.cpp ${CMAKE_CURRENT_LIST_DIR}/ledgerline.h ${CMAKE_CURRENT_LIST_DIR}/letring.cpp diff --git a/src/engraving/libmscore/measure.cpp b/src/engraving/libmscore/measure.cpp index 05777a50c3..ae74bc5727 100644 --- a/src/engraving/libmscore/measure.cpp +++ b/src/engraving/libmscore/measure.cpp @@ -55,7 +55,6 @@ #include "key.h" #include "keysig.h" #include "layoutbreak.h" -#include "layout.h" #include "note.h" #include "ottava.h" #include "page.h" diff --git a/src/engraving/libmscore/score.cpp b/src/engraving/libmscore/score.cpp index 4eba7e1bab..744fcbfda2 100644 --- a/src/engraving/libmscore/score.cpp +++ b/src/engraving/libmscore/score.cpp @@ -5280,32 +5280,6 @@ void Score::connectTies(bool silent) } } } -#if 0 // chords are set in tremolo->layout() - // connect two note tremolos - Tremolo* tremolo = c->tremolo(); - if (tremolo && tremolo->twoNotes() && !tremolo->chord2()) { - for (Segment* ls = s->next1(st); ls; ls = ls->next1(st)) { - Element* element = ls->element(i); - if (!element) { - continue; - } - if (!element->isChord()) { - qDebug("cannot connect tremolo"); - } else { - Chord* nc = toChord(element); - nc->setTremolo(tremolo); - tremolo->setChords(c, nc); - // cross-measure tremolos are not supported - // but can accidentally result from copy & paste - // remove them now - if (c->measure() != nc->measure()) { - c->remove(tremolo); - } - } - break; - } - } -#endif } } } @@ -5315,6 +5289,50 @@ mu::score::AccessibleScore* Score::accessible() const return m_accessible; } +//--------------------------------------------------------- +// relayoutForStyles +/// some styles can't properly apply if score hasn't been laid out yet, +/// so temporarily disable them and then reenable after layout +/// (called during score load) +//--------------------------------------------------------- + +void Score::relayoutForStyles() +{ + std::vector stylesToTemporarilyDisable; + + for (Sid sid : { Sid::createMultiMeasureRests, Sid::mrNumberSeries }) { + // only necessary if boolean style is true + if (styleB(sid)) { + stylesToTemporarilyDisable.push_back(sid); + } + } + + if (!stylesToTemporarilyDisable.empty()) { + for (Sid sid : stylesToTemporarilyDisable) { + style().set(sid, false); // temporarily disable + } + doLayout(); + for (Sid sid : stylesToTemporarilyDisable) { + style().set(sid, true); // and immediately reenable + } + } +} + +//--------------------------------------------------------- +// doLayout +// do a complete (re-) layout +//--------------------------------------------------------- + +void Score::doLayout() +{ + doLayoutRange(Fraction(0, 1), Fraction(-1, 1)); +} + +void Score::doLayoutRange(const Fraction& st, const Fraction& et) +{ + m_layout.doLayoutRange(st, et); +} + UndoStack* Score::undoStack() const { return _masterScore->undoStack(); } const RepeatList& Score::repeatList() const { return _masterScore->repeatList(); } const RepeatList& Score::repeatList2() const { return _masterScore->repeatList2(); } diff --git a/src/engraving/libmscore/score.h b/src/engraving/libmscore/score.h index c3570a2c90..6be5ea083f 100644 --- a/src/engraving/libmscore/score.h +++ b/src/engraving/libmscore/score.h @@ -544,8 +544,6 @@ private: void cmdMoveRest(Rest*, Direction); void cmdMoveLyrics(Lyrics*, Direction); - void createMMRest(Measure*, Measure*, const Fraction&); - void checkSlurs(); void checkScore(); diff --git a/src/engraving/libmscore/textbase.cpp b/src/engraving/libmscore/textbase.cpp index 7a4642c634..58f2e86ff0 100644 --- a/src/engraving/libmscore/textbase.cpp +++ b/src/engraving/libmscore/textbase.cpp @@ -2505,6 +2505,7 @@ Pid TextBase::propertyId(const QStringRef& name) const if (name == "text") { return Pid::TEXT; } + for (Pid pid : TextBasePropertyId) { if (propertyName(pid) == name) { return pid; diff --git a/src/engraving/style/styledef.cpp b/src/engraving/style/styledef.cpp index 4569ee4c4a..d46ec4a8c4 100644 --- a/src/engraving/style/styledef.cpp +++ b/src/engraving/style/styledef.cpp @@ -38,7 +38,6 @@ #include "libmscore/clef.h" #include "libmscore/textlinebase.h" #include "libmscore/tuplet.h" -#include "libmscore/layout.h" #include "libmscore/property.h" #include "libmscore/undo.h" diff --git a/src/engraving/style/styledef.h b/src/engraving/style/styledef.h index 8a8e99a0c4..9500b86d37 100644 --- a/src/engraving/style/styledef.h +++ b/src/engraving/style/styledef.h @@ -1467,7 +1467,6 @@ enum class VerticalAlignRange { SEGMENT, MEASURE, SYSTEM }; - //--------------------------------------------------------- // StyledProperty /// \cond PLUGIN_API \private \endcond diff --git a/src/framework/accessibility/dev/accessibledevmodel.cpp b/src/framework/accessibility/dev/accessibledevmodel.cpp index 1346bcd27c..2d7a3f0ea4 100644 --- a/src/framework/accessibility/dev/accessibledevmodel.cpp +++ b/src/framework/accessibility/dev/accessibledevmodel.cpp @@ -22,6 +22,7 @@ #include "accessibledevmodel.h" #include +#include #include "log.h" diff --git a/src/framework/global/globalmodule.cpp b/src/framework/global/globalmodule.cpp index dfba77fbe1..9cdf2d95c3 100644 --- a/src/framework/global/globalmodule.cpp +++ b/src/framework/global/globalmodule.cpp @@ -43,6 +43,7 @@ #include "diagnostics/idiagnosticspathsregister.h" using namespace mu::framework; +using namespace mu::modularity; static std::shared_ptr s_globalConf = std::make_shared(); diff --git a/src/framework/midi/internal/platform/lin/alsamidiinport.cpp b/src/framework/midi/internal/platform/lin/alsamidiinport.cpp index 7474a461ea..455542a1ab 100644 --- a/src/framework/midi/internal/platform/lin/alsamidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/alsamidiinport.cpp @@ -46,7 +46,7 @@ AlsaMidiInPort::~AlsaMidiInPort() void AlsaMidiInPort::init() { - m_alsa = std::unique_ptr(new Alsa()); + m_alsa = std::shared_ptr(new Alsa()); m_devicesListener.startWithCallback([this]() { return devices(); diff --git a/src/framework/midi/internal/platform/lin/alsamidiinport.h b/src/framework/midi/internal/platform/lin/alsamidiinport.h index 2affff191d..066dec7e8c 100644 --- a/src/framework/midi/internal/platform/lin/alsamidiinport.h +++ b/src/framework/midi/internal/platform/lin/alsamidiinport.h @@ -58,7 +58,7 @@ private: bool deviceExists(const MidiDeviceID& deviceId) const; struct Alsa; - std::unique_ptr m_alsa; + std::shared_ptr m_alsa; MidiDeviceID m_deviceID; std::shared_ptr m_thread; std::atomic m_running{ false }; diff --git a/src/framework/midi/internal/platform/lin/alsamidioutport.cpp b/src/framework/midi/internal/platform/lin/alsamidioutport.cpp index d5046604c1..13d650d629 100644 --- a/src/framework/midi/internal/platform/lin/alsamidioutport.cpp +++ b/src/framework/midi/internal/platform/lin/alsamidioutport.cpp @@ -46,7 +46,7 @@ AlsaMidiOutPort::~AlsaMidiOutPort() void AlsaMidiOutPort::init() { - m_alsa = std::unique_ptr(new Alsa()); + m_alsa = std::shared_ptr(new Alsa()); m_devicesListener.startWithCallback([this]() { return devices(); diff --git a/src/framework/midi/internal/platform/lin/alsamidioutport.h b/src/framework/midi/internal/platform/lin/alsamidioutport.h index 81ceba3959..9c5b9c7539 100644 --- a/src/framework/midi/internal/platform/lin/alsamidioutport.h +++ b/src/framework/midi/internal/platform/lin/alsamidioutport.h @@ -51,7 +51,7 @@ private: bool deviceExists(const MidiDeviceID& deviceId) const; struct Alsa; - std::unique_ptr m_alsa; + std::shared_ptr m_alsa; MidiDeviceID m_deviceID; async::Notification m_devicesChanged; diff --git a/src/framework/midi/midimodule.cpp b/src/framework/midi/midimodule.cpp index 989bc77c0a..1a1691e994 100644 --- a/src/framework/midi/midimodule.cpp +++ b/src/framework/midi/midimodule.cpp @@ -22,7 +22,6 @@ #include "midimodule.h" #include -#include "log.h" #include "modularity/ioc.h" @@ -33,6 +32,8 @@ #include "ui/iuiengine.h" #include "view/devtools/midiportdevmodel.h" +#include "log.h" + using namespace mu::midi; static std::shared_ptr s_configuration = std::make_shared(); diff --git a/src/framework/ui/view/navigationpanel.cpp b/src/framework/ui/view/navigationpanel.cpp index b67e8b56cd..4f80d17ea8 100644 --- a/src/framework/ui/view/navigationpanel.cpp +++ b/src/framework/ui/view/navigationpanel.cpp @@ -23,11 +23,13 @@ #include +#include "accessibility/iaccessible.h" #include "navigationsection.h" #include "translation.h" #include "log.h" using namespace mu::ui; +using namespace mu::accessibility; NavigationPanel::NavigationPanel(QObject* parent) : AbstractNavigation(parent) diff --git a/src/notation/view/widgets/editstaff.cpp b/src/notation/view/widgets/editstaff.cpp index 84ac9edc54..8deb21f68b 100644 --- a/src/notation/view/widgets/editstaff.cpp +++ b/src/notation/view/widgets/editstaff.cpp @@ -33,13 +33,15 @@ #include "libmscore/utils.h" #include "libmscore/undo.h" #include "libmscore/iname.h" +#include "libmscore/system.h" -#include "log.h" #include "translation.h" #include "ui/view/iconcodes.h" #include "widgetstatestore.h" +#include "log.h" + using namespace mu::notation; using namespace mu::ui; diff --git a/src/notation/view/widgets/editstyle.cpp b/src/notation/view/widgets/editstyle.cpp index bc00d58eb8..d8d975987b 100644 --- a/src/notation/view/widgets/editstyle.cpp +++ b/src/notation/view/widgets/editstyle.cpp @@ -30,15 +30,14 @@ #include "fontStyleSelect.h" #include "framework/global/widgetstatestore.h" #include "libmscore/figuredbass.h" -#include "libmscore/layout.h" #include "libmscore/scorefont.h" #include "libmscore/sym.h" #include "libmscore/realizedharmony.h" -#include "log.h" #include "offsetSelect.h" #include "settings.h" #include "translation.h" #include "ui/view/iconcodes.h" +#include "log.h" using namespace mu::notation; using namespace mu::ui;