From 808780393c820395c2e8db1dd7ba747726ce32ce Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 2 Jun 2020 19:33:29 -0400 Subject: [PATCH] Prepare for changes to multimeasure rests Add class MMRest and ElementType::MMREST (fix #306192: Lyrics entry with multimeasure rest selected) Add new Style page Rename local variables and add comments in createMMRest() --- inspectors/view/ui/inspector.cpp | 3 + libmscore/CMakeLists.txt | 4 +- libmscore/cmd.cpp | 1 + libmscore/edit.cpp | 3 +- libmscore/element.cpp | 4 + libmscore/layout.cpp | 328 ++++++++++++++++--------------- libmscore/measure.cpp | 65 +++--- libmscore/mmrest.cpp | 227 +++++++++++++++++++++ libmscore/mmrest.h | 55 ++++++ libmscore/navigate.cpp | 5 +- libmscore/read114.cpp | 41 ++-- libmscore/read206.cpp | 37 ++-- libmscore/rest.cpp | 145 +++----------- libmscore/rest.h | 8 +- libmscore/score.cpp | 7 +- libmscore/scoreElement.cpp | 1 + libmscore/scoreElement.h | 19 +- libmscore/segment.cpp | 11 +- libmscore/select.cpp | 5 +- libmscore/types.h | 1 + mscore/debugger/debugger.cpp | 1 - mscore/debugger/rest.ui | 26 --- mscore/editstyle.cpp | 3 +- mscore/editstyle.ui | 318 ++++++++++++++++++------------ mscore/scoreview.cpp | 5 +- mtest/scripting/p1.log.ref | 4 +- 26 files changed, 806 insertions(+), 521 deletions(-) create mode 100644 libmscore/mmrest.cpp create mode 100644 libmscore/mmrest.h diff --git a/inspectors/view/ui/inspector.cpp b/inspectors/view/ui/inspector.cpp index ee8910bde610d..a7b7c87cb0757 100644 --- a/inspectors/view/ui/inspector.cpp +++ b/inspectors/view/ui/inspector.cpp @@ -216,6 +216,9 @@ void Inspector::update(Score* s) case ElementType::REST: ie = new InspectorRest(this); break; + case ElementType::MMREST: + ie = new InspectorMMRest(this); + break; case ElementType::CLEF: ie = new InspectorClef(this); break; diff --git a/libmscore/CMakeLists.txt b/libmscore/CMakeLists.txt index ddd75fe6ca90a..3cd8b6ef87d02 100644 --- a/libmscore/CMakeLists.txt +++ b/libmscore/CMakeLists.txt @@ -49,7 +49,7 @@ add_library ( elementmap.h excerpt.h fermata.h fifo.h figuredbass.h fingering.h fraction.h fret.h glissando.h groups.h hairpin.h harmony.h hook.h icon.h image.h imageStore.h iname.h input.h instrchange.h instrtemplate.h instrument.h interval.h jump.h key.h keylist.h keysig.h lasso.h layout.h layoutbreak.h ledgerline.h letring.h line.h location.h - lyrics.h marker.h mcursor.h measure.h measurebase.h mscore.h mscoreview.h musescoreCore.h navigate.h note.h notedot.h + lyrics.h marker.h mcursor.h measure.h measurebase.h mmrest.h mscore.h mscoreview.h musescoreCore.h navigate.h note.h notedot.h noteevent.h noteline.h ossia.h ottava.h page.h palmmute.h part.h pedal.h pitch.h pitchspelling.h pitchvalue.h pos.h property.h range.h read206.h realizedharmony.h rehearsalmark.h repeat.h repeatlist.h rest.h revisions.h score.h scoreElement.h segment.h segmentlist.h select.h sequencer.h shadownote.h shape.h sig.h slur.h slurtie.h spacer.h spanner.h spannermap.h spatium.h @@ -69,7 +69,7 @@ add_library ( instrtemplate.cpp instrument.cpp interval.cpp key.cpp keysig.cpp lasso.cpp layoutbreak.cpp layout.cpp line.cpp lyrics.cpp measurebase.cpp - measure.cpp navigate.cpp note.cpp noteevent.cpp ottava.cpp + measure.cpp mmrest.cpp navigate.cpp note.cpp noteevent.cpp ottava.cpp page.cpp part.cpp pedal.cpp letring.cpp vibrato.cpp palmmute.cpp pitch.cpp pitchspelling.cpp rendermidi.cpp repeat.cpp repeatlist.cpp rest.cpp score.cpp segment.cpp select.cpp shadownote.cpp slur.cpp tie.cpp slurtie.cpp diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index f625951fb81c6..c354cc9da976c 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -2369,6 +2369,7 @@ Element* Score::move(const QString& cmd) break; case ElementType::CHORD: // a chord or a rest are valid targets case ElementType::REST: + case ElementType::MMREST: trg = el; cr = toChordRest(trg); break; diff --git a/libmscore/edit.cpp b/libmscore/edit.cpp index 96eed287cdea5..89d47f90922c7 100644 --- a/libmscore/edit.cpp +++ b/libmscore/edit.cpp @@ -156,6 +156,7 @@ Fraction Score::pos() // fall through case ElementType::REPEAT_MEASURE: case ElementType::REST: + case ElementType::MMREST: case ElementType::CHORD: return toChordRest(el)->tick(); default: @@ -1810,7 +1811,7 @@ void Score::deleteItem(Element* el) undoAddCR(rest, segment->measure(), segment->tick()); } // fall through - + case ElementType::MMREST: case ElementType::REST: // // only allow for voices != 0 diff --git a/libmscore/element.cpp b/libmscore/element.cpp index 2730142409f2e..3b59b134cde8f 100644 --- a/libmscore/element.cpp +++ b/libmscore/element.cpp @@ -48,6 +48,7 @@ #include "lyrics.h" #include "marker.h" #include "measure.h" +#include "mmrest.h" #include "mscore.h" #include "notedot.h" #include "note.h" @@ -1104,6 +1105,7 @@ Element* Element::create(ElementType type, Score* score) case ElementType::FSYMBOL: return new FSymbol(score); case ElementType::CHORD: return new Chord(score); case ElementType::REST: return new Rest(score); + case ElementType::MMREST: return new MMRest(score); case ElementType::SPACER: return new Spacer(score); case ElementType::STAFF_STATE: return new StaffState(score); case ElementType::TEMPO_TEXT: return new TempoText(score); @@ -1776,6 +1778,7 @@ Element* Element::nextSegmentElement() } return p; case ElementType::REST: + case ElementType::MMREST: return p; case ElementType::CHORD: { Chord* c = toChord(p); @@ -1823,6 +1826,7 @@ Element* Element::prevSegmentElement() } return p; case ElementType::REST: + case ElementType::MMREST: return p; case ElementType::CHORD: { Chord* c = toChord(p); diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 4b103369b0b2f..808299034ec1a 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -27,6 +27,7 @@ #include "lyrics.h" #include "marker.h" #include "measure.h" +#include "mmrest.h" #include "mscore.h" #include "notedot.h" #include "note.h" @@ -1856,108 +1857,117 @@ System* Score::getNextSystem(LayoutContext& lc) //--------------------------------------------------------- // createMMRest -// create a multi measure rest from m to lm (inclusive) +// create a multimeasure rest +// from firstMeasure to lastMeasure (inclusive) //--------------------------------------------------------- -void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) +void Score::createMMRest(Measure* firstMeasure, Measure* lastMeasure, const Fraction& len) { - int n = 1; - if (m != lm) { - for (Measure* mm = m->nextMeasure(); mm; mm = mm->nextMeasure()) { - ++n; - mm->setMMRestCount(-1); - if (mm->mmRest()) { - undo(new ChangeMMRest(mm, 0)); - } - if (mm == lm) { + 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; } } } - Measure* mmr = m->mmRest(); - if (mmr) { + // mmrMeasure coexists with n undisplayed measures of rests + Measure* mmrMeasure = firstMeasure->mmRest(); + if (mmrMeasure) { // reuse existing mmrest - if (mmr->ticks() != len) { - Segment* s = mmr->findSegmentR(SegmentType::EndBarLine, mmr->ticks()); + if (mmrMeasure->ticks() != len) { + Segment* s = mmrMeasure->findSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks()); // adjust length - mmr->setTicks(len); + mmrMeasure->setTicks(len); // move existing end barline if (s) { s->setRtick(len); } } - mmr->removeSystemTrailer(); + mmrMeasure->removeSystemTrailer(); } else { - mmr = new Measure(this); - mmr->setTicks(len); - mmr->setTick(m->tick()); - undo(new ChangeMMRest(m, mmr)); - } - mmr->setTimesig(m->timesig()); - mmr->setPageBreak(lm->pageBreak()); - mmr->setLineBreak(lm->lineBreak()); - mmr->setMMRestCount(n); - mmr->setNo(m->no()); - - Segment* ss = lm->findSegmentR(SegmentType::EndBarLine, lm->ticks()); - if (ss) { - Segment* ds = mmr->undoGetSegmentR(SegmentType::EndBarLine, mmr->ticks()); + 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 = ss->element(staffIdx * VOICES); + Element* e = lastMeasureEndBarlineSeg->element(staffIdx * VOICES); if (e) { bool generated = e->generated(); - if (!ds->element(staffIdx * VOICES)) { - Element* ee = generated ? e->clone() : e->linkedClone(); - ee->setGenerated(generated); - ee->setParent(ds); - undoAddElement(ee); + if (!mmrEndBarlineSeg->element(staffIdx * VOICES)) { + Element* eClone = generated ? e->clone() : e->linkedClone(); + eClone->setGenerated(generated); + eClone->setParent(mmrEndBarlineSeg); + undoAddElement(eClone); } else { - BarLine* bd = toBarLine(ds->element(staffIdx * VOICES)); - BarLine* bs = toBarLine(e); - if (!generated && !bd->links()) { - undo(new Link(bd, bs)); + BarLine* mmrEndBarline = toBarLine(mmrEndBarlineSeg->element(staffIdx * VOICES)); + BarLine* lastMeasureEndBarline = toBarLine(e); + if (!generated && !mmrEndBarline->links()) { + undo(new Link(mmrEndBarline, lastMeasureEndBarline)); } - if (bd->barLineType() != bs->barLineType()) { + if (mmrEndBarline->barLineType() != lastMeasureEndBarline->barLineType()) { // change directly when generating mmrests, do not change underlying measures or follow links - undo(new ChangeProperty(bd, Pid::BARLINE_TYPE, QVariant::fromValue(bs->barLineType()), - PropertyFlags::NOSTYLE)); - undo(new ChangeProperty(bd, Pid::GENERATED, generated, PropertyFlags::NOSTYLE)); + undo(new ChangeProperty(mmrEndBarline, Pid::BARLINE_TYPE, QVariant::fromValue(lastMeasureEndBarline->barLineType()), PropertyFlags::NOSTYLE)); + undo(new ChangeProperty(mmrEndBarline, Pid::GENERATED, generated, PropertyFlags::NOSTYLE)); } } } } } - Segment* clefSeg = lm->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, lm->ticks()); - if (clefSeg) { - Segment* mmrClefSeg = mmr->undoGetSegment(clefSeg->segmentType(), lm->endTick()); + // + // 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 = clefSeg->element(track); + Element* e = lastMeasureClefSeg->element(track); if (e && e->isClef()) { - Clef* clef = toClef(e); + Clef* lastMeasureClef = toClef(e); if (!mmrClefSeg->element(track)) { - Clef* mmrClef = clef->generated() ? clef->clone() : toClef(clef->linkedClone()); + Clef* mmrClef = lastMeasureClef->generated() ? lastMeasureClef->clone() : toClef(lastMeasureClef->linkedClone()); mmrClef->setParent(mmrClefSeg); undoAddElement(mmrClef); } else { Clef* mmrClef = toClef(mmrClefSeg->element(track)); - mmrClef->setClefType(clef->clefType()); - mmrClef->setShowCourtesy(clef->showCourtesy()); + mmrClef->setClefType(lastMeasureClef->clefType()); + mmrClef->setShowCourtesy(lastMeasureClef->showCourtesy()); } } } } - mmr->setRepeatStart(m->repeatStart() || lm->repeatStart()); - mmr->setRepeatEnd(m->repeatEnd() || lm->repeatEnd()); - mmr->setSectionBreak(lm->sectionBreak()); - - ElementList oldList = mmr->takeElements(); - ElementList newList = lm->el(); + mmrMeasure->setRepeatStart(firstMeasure->repeatStart() || lastMeasure->repeatStart()); + mmrMeasure->setRepeatEnd(firstMeasure->repeatEnd() || lastMeasure->repeatEnd()); + mmrMeasure->setSectionBreak(lastMeasure->sectionBreak()); - for (Element* e : m->el()) { + // + // copy markers to mmrMeasure + // + ElementList oldList = mmrMeasure->takeElements(); + ElementList newList = lastMeasure->el(); + for (Element* e : firstMeasure->el()) { if (e->isMarker()) { newList.push_back(e); } @@ -1966,7 +1976,7 @@ void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) bool found = false; for (Element* ee : oldList) { if (ee->type() == e->type() && ee->subtype() == e->subtype()) { - mmr->add(ee); + mmrMeasure->add(ee); auto i = std::find(oldList.begin(), oldList.end(), ee); if (i != oldList.end()) { oldList.erase(i); @@ -1976,162 +1986,160 @@ void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) } } if (!found) { - mmr->add(e->clone()); + mmrMeasure->add(e->clone()); } } for (Element* e : oldList) { delete e; } - Segment* s = mmr->undoGetSegmentR(SegmentType::ChordRest, Fraction(0,1)); + 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) { - Rest* r = new Rest(this); - r->setDurationType(TDuration::DurationType::V_MEASURE); - r->setTicks(mmr->ticks()); - r->setTrack(track); - r->setParent(s); - undo(new AddElement(r)); + 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)); } } // - // check for clefs + // further check for clefs // - Segment* cs = lm->findSegmentR(SegmentType::Clef, lm->ticks()); - Segment* ns = mmr->findSegment(SegmentType::Clef, lm->endTick()); - if (cs) { - if (ns == 0) { - ns = mmr->undoGetSegmentR(SegmentType::Clef, lm->ticks()); - } - ns->setEnabled(cs->enabled()); - ns->setTrailer(cs->trailer()); + 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(cs->element(track)); + Clef* clef = toClef(underlyingSeg->element(track)); if (clef) { - if (ns->element(track) == 0) { - ns->add(clef->clone()); + if (mmrSeg->element(track) == 0) { + mmrSeg->add(clef->clone()); } else { //TODO: check if same clef } } } - } else if (ns) { + } else if (mmrSeg) { // TODO: remove elements from ns? - undo(new RemoveElement(ns)); + undo(new RemoveElement(mmrSeg)); } // // check for time signature // - cs = m->findSegmentR(SegmentType::TimeSig, Fraction(0,1)); - ns = mmr->findSegment(SegmentType::TimeSig, m->tick()); - if (cs) { - if (ns == 0) { - ns = mmr->undoGetSegmentR(SegmentType::TimeSig, Fraction(0,1)); - } - ns->setEnabled(cs->enabled()); - ns->setHeader(cs->header()); + 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* ts = toTimeSig(cs->element(track)); - if (ts) { - TimeSig* nts = toTimeSig(ns->element(track)); - if (!nts) { - nts = ts->generated() ? ts->clone() : toTimeSig(ts->linkedClone()); - nts->setParent(ns); - undo(new AddElement(nts)); + 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 { - nts->setSig(ts->sig(), ts->timeSigType()); - nts->layout(); + mmrTimeSig->setSig(underlyingTimeSig->sig(), underlyingTimeSig->timeSigType()); + mmrTimeSig->layout(); } } } - } else if (ns) { - // TODO: remove elements from ns? - undo(new RemoveElement(ns)); + } else if (mmrSeg) { + // TODO: remove elements from mmrSeg? + undo(new RemoveElement(mmrSeg)); } // // check for ambitus // - cs = m->findSegmentR(SegmentType::Ambitus, Fraction(0,1)); - ns = mmr->findSegment(SegmentType::Ambitus, m->tick()); - if (cs) { - if (ns == 0) { - ns = mmr->undoGetSegmentR(SegmentType::Ambitus, Fraction(0,1)); + 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* a = toAmbitus(cs->element(track)); - if (a) { - Ambitus* na = toAmbitus(ns->element(track)); - if (!na) { - na = a->clone(); - na->setParent(ns); - undo(new AddElement(na)); - } else { - na->initFrom(a); - na->layout(); + 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)); + mmrAmbitus->initFrom(underlyingAmbitus); + mmrAmbitus->layout(); } } } - } else if (ns) { - // TODO: remove elements from ns? - undo(new RemoveElement(ns)); + } else if (mmrSeg) { + // TODO: remove elements from mmrSeg? + undo(new RemoveElement(mmrSeg)); } // // check for key signature // - cs = m->findSegmentR(SegmentType::KeySig, Fraction(0,1)); - ns = mmr->findSegmentR(SegmentType::KeySig, Fraction(0,1)); - if (cs) { - if (ns == 0) { - ns = mmr->undoGetSegmentR(SegmentType::KeySig, Fraction(0,1)); - } - ns->setEnabled(cs->enabled()); - ns->setHeader(cs->header()); + 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* ks = toKeySig(cs->element(track)); - if (ks) { - KeySig* nks = toKeySig(ns->element(track)); - if (!nks) { - nks = ks->generated() ? ks->clone() : toKeySig(ks->linkedClone()); - nks->setParent(ns); - nks->setGenerated(true); - undo(new AddElement(nks)); + 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 (!(nks->keySigEvent() == ks->keySigEvent())) { - bool addKey = ks->isChange(); - undo(new ChangeKeySig(nks, ks->keySigEvent(), nks->showCourtesy(), addKey)); + if (!(mmrKeySig->keySigEvent() == underlyingKeySig->keySigEvent())) { + bool addKey = underlyingKeySig->isChange(); + undo(new ChangeKeySig(mmrKeySig, underlyingKeySig->keySigEvent(), mmrKeySig->showCourtesy(), addKey)); } } } } - } else if (ns) { - ns->setEnabled(false); - // TODO: remove elements from ns, then delete ns + } 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(ns)); + //undo(new RemoveElement(mmrSeg)); } - mmr->checkHeader(); - mmr->checkTrailer(); + mmrMeasure->checkHeader(); + mmrMeasure->checkTrailer(); // // check for rehearsal mark etc. // - cs = m->findSegmentR(SegmentType::ChordRest, Fraction(0,1)); - if (cs) { + underlyingSeg = firstMeasure->findSegmentR(SegmentType::ChordRest, Fraction(0,1)); + if (underlyingSeg) { // clone elements from underlying measure to mmr - for (Element* e : cs->annotations()) { + for (Element* e : underlyingSeg->annotations()) { // look at elements in underlying measure - if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() - || e->isInstrumentChange())) { + if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange())) { continue; } // try to find a match in mmr @@ -2144,9 +2152,9 @@ void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) } // add to mmr if no match found if (!found) { - Element* ne = e->linkedClone(); - ne->setParent(s); - undo(new AddElement(ne)); + Element* eClone = e->linkedClone(); + eClone->setParent(s); + undo(new AddElement(eClone)); } } @@ -2154,13 +2162,12 @@ void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) // 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())) { + 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 : cs->annotations()) { + for (Element* ee : underlyingSeg->annotations()) { if (e->linkList().contains(ee)) { found = true; break; @@ -2172,9 +2179,10 @@ void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len) } } } - MeasureBase* nm = _showVBox ? lm->next() : lm->nextMeasure(); - mmr->setNext(nm); - mmr->setPrev(m->prev()); + + MeasureBase* nm = _showVBox ? lastMeasure->next() : lastMeasure->nextMeasure(); + mmrMeasure->setNext(nm); + mmrMeasure->setPrev(firstMeasure->prev()); } //--------------------------------------------------------- diff --git a/libmscore/measure.cpp b/libmscore/measure.cpp index a911cf14b72da..e5100de5300af 100644 --- a/libmscore/measure.cpp +++ b/libmscore/measure.cpp @@ -51,6 +51,7 @@ #include "pitchspelling.h" #include "repeat.h" #include "rest.h" +#include "mmrest.h" #include "score.h" #include "segment.h" #include "select.h" @@ -981,6 +982,7 @@ void Measure::remove(Element* e) case ElementType::CLEF: case ElementType::CHORD: case ElementType::REST: + case ElementType::MMREST: case ElementType::TIMESIG: for (Segment* segment = first(); segment; segment = segment->next()) { int staves = score()->nstaves(); @@ -2203,30 +2205,39 @@ void Measure::readVoice(XmlReader& e, int staffIdx, bool irregular) fermata = nullptr; } } else if (tag == "Rest") { - Rest* rest = new Rest(score()); - rest->setDurationType(TDuration::DurationType::V_MEASURE); - rest->setTicks(timesig() / timeStretch); - rest->setTrack(e.track()); - rest->read(e); - if (startingBeam) { - startingBeam->add(rest); // also calls rest->setBeam(startingBeam) - startingBeam = nullptr; - } - segment = getSegment(SegmentType::ChordRest, e.tick()); - segment->add(rest); - if (fermata) { - segment->add(fermata); - fermata = nullptr; - } - - if (!rest->ticks().isValid()) { // hack + if (isMMRest()) { + MMRest* mmr = new MMRest(score()); + mmr->setTrack(e.track()); + mmr->read(e); + segment = getSegment(SegmentType::ChordRest, e.tick()); + segment->add(mmr); + e.incTick(mmr->actualTicks()); + } else { + Rest* rest = new Rest(score()); + rest->setDurationType(TDuration::DurationType::V_MEASURE); rest->setTicks(timesig() / timeStretch); - } + rest->setTrack(e.track()); + rest->read(e); + if (startingBeam) { + startingBeam->add(rest); // also calls rest->setBeam(startingBeam) + startingBeam = nullptr; + } + segment = getSegment(SegmentType::ChordRest, e.tick()); + segment->add(rest); + if (fermata) { + segment->add(fermata); + fermata = nullptr; + } - if (tuplet) { - tuplet->add(rest); + if (!rest->ticks().isValid()) { // hack + rest->setTicks(timesig() / timeStretch); + } + + if (tuplet) { + tuplet->add(rest); + } + e.incTick(rest->actualTicks()); } - e.incTick(rest->actualTicks()); } else if (tag == "Breath") { Breath* breath = new Breath(score()); breath->setTrack(e.track()); @@ -3505,8 +3516,8 @@ void Measure::stretchMeasure(qreal targetWidth) } ElementType t = e->type(); int staffIdx = e->staffIdx(); - if (t == ElementType::REPEAT_MEASURE - || (t == ElementType::REST && (isMMRest() || toRest(e)->isFullMeasureRest()))) { + if (t == ElementType::REPEAT_MEASURE || (t == ElementType::MMREST) + || (t == ElementType::REST && toRest(e)->isFullMeasureRest())) { // // element has to be centered in free space // x1 - left measure position of free space @@ -3525,14 +3536,14 @@ void Measure::stretchMeasure(qreal targetWidth) qreal x2 = s2 ? s2->x() - s2->minLeft() : targetWidth; if (isMMRest()) { - Rest* rest = toRest(e); + MMRest* mmrest = toMMRest(e); // // center multi measure rest // qreal d = score()->styleP(Sid::multiMeasureRestMargin); qreal w = x2 - x1 - 2 * d; - rest->layoutMMRest(w); + mmrest->layout(w); e->setPos(x1 - s.x() + d, e->staff()->height() * .5); // center vertically in measure s.createShape(staffIdx); } else { // if (rest->isFullMeasureRest()) { @@ -4411,10 +4422,10 @@ void Measure::computeMinWidth(Segment* s, qreal x, bool isSystemHeader) Segment* seg = findSegmentR(SegmentType::ChordRest, Fraction(0,1)); const int nstaves = score()->nstaves(); for (int st = 0; st < nstaves; ++st) { - Rest* mmRest = toRest(seg->element(staff2track(st))); + MMRest* mmRest = toMMRest(seg->element(staff2track(st))); if (mmRest) { mmRest->rxpos() = 0; - mmRest->layoutMMRest(score()->styleP(Sid::minMMRestWidth) * mag()); + mmRest->layout(score()->styleP(Sid::minMMRestWidth) * mag()); mmRest->segment()->createShapes(); } } diff --git a/libmscore/mmrest.cpp b/libmscore/mmrest.cpp new file mode 100644 index 0000000000000..ca1108a937aff --- /dev/null +++ b/libmscore/mmrest.cpp @@ -0,0 +1,227 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2020 MuseScore BVBA +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 +// as published by the Free Software Foundation and appearing in +// the file LICENCE.GPL +//============================================================================= + +#include "mmrest.h" +#include "measure.h" +#include "score.h" +#include "undo.h" +#include "utils.h" + +namespace Ms { +//--------------------------------------------------------- +// mmRestStyle +//--------------------------------------------------------- + +static const ElementStyle mmRestStyle { + { Sid::mmRestNumberPos, Pid::MMREST_NUMBER_POS }, +}; + +//--------------------------------------------------------- +// MMRest +//-------------------------------------------------------- + +MMRest::MMRest(Score* s) + : Rest(s) +{ + _mmWidth = 0; + if (score()) { + initElementStyle(&mmRestStyle); + } +} + +MMRest::MMRest(const MMRest& r, bool link) + : Rest(r, link) +{ + if (link) { + score()->undo(new Link(this, const_cast(&r))); + setAutoplace(true); + } + _mmWidth = r._mmWidth; +} + +//--------------------------------------------------------- +// MMRest::draw +//--------------------------------------------------------- + +void MMRest::draw(QPainter* painter) const +{ + if (shouldNotBeDrawn() || (track() % VOICES)) { //only on voice 1 + return; + } + + qreal _spatium = spatium(); + painter->setPen(curColor()); + + // draw number + int n = measure()->mmRestCount(); + std::vector&& s = toTimeSigString(QString("%1").arg(n)); + qreal y = _mmRestNumberPos * spatium() - staff()->height() * .5; + qreal x = (_mmWidth - symBbox(s).width()) * .5; + drawSymbols(s, painter, QPointF(x, y)); + + // draw horizontal line + qreal pw = _spatium * .7; + QPen pen(painter->pen()); + pen.setWidthF(pw); + painter->setPen(pen); + qreal x1 = pw * .5; + qreal x2 = _mmWidth - x1; + if (_mmRestNumberPos > 0.7 && _mmRestNumberPos < 3.3) { // hack for when number encounters horizontal line + qreal gapDistance = symBbox(s).width() * .5 + _spatium; + qreal midpoint = (x1 + x2) * .5; + painter->drawLine(QLineF(x1, 0.0, midpoint - gapDistance, 0.0)); + painter->drawLine(QLineF(midpoint + gapDistance, 0.0, x2, 0.0)); + } else { + painter->drawLine(QLineF(x1, 0.0, x2, 0.0)); + } + + // draw vertical lines + pen.setWidthF(_spatium * .2); + painter->setPen(pen); + painter->drawLine(QLineF(0.0, -_spatium, 0.0, _spatium)); + painter->drawLine(QLineF(_mmWidth, -_spatium, _mmWidth, _spatium)); +} + +//--------------------------------------------------------- +// layout +//--------------------------------------------------------- + +void MMRest::layout() +{ + for (Element* e : el()) { + e->layout(); + } + _mmWidth = score()->styleP(Sid::minMMRestWidth) * mag(); + // setbbox(QRectF(0.0, -_spatium, _mmWidth, 2.0 * _spatium)); + return; +} + +void MMRest::layout(qreal val) +{ + // static const qreal verticalLineWidth = .2; + + qreal _spatium = spatium(); + _mmWidth = val; + // qreal h = _spatium * (2 + verticalLineWidth); + // qreal w = _mmWidth + _spatium * verticalLineWidth * .5; + // bbox().setRect(-_spatium * verticalLineWidth * .5, -h * .5, w, h); + bbox().setRect(0.0, -_spatium, _mmWidth, _spatium * 2); + + // text + // qreal y = -_spatium * 2.5 - staff()->height() *.5; + // addbbox(QRectF(0, y, w, _spatium * 2)); // approximation +} + +//--------------------------------------------------------- +// MMRest::write +//--------------------------------------------------------- + +void MMRest::write(XmlWriter& xml) const +{ + xml.stag("Rest"); + ChordRest::writeProperties(xml); + el().write(xml); + xml.etag(); +} + +//--------------------------------------------------------- +// propertyDefault +//--------------------------------------------------------- + +QVariant MMRest::propertyDefault(Pid propertyId) const +{ + switch (propertyId) { + case Pid::MMREST_NUMBER_POS: + return score()->styleV(Sid::mmRestNumberPos); + default: + return Rest::propertyDefault(propertyId); + } +} + +//--------------------------------------------------------- +// resetProperty +//--------------------------------------------------------- + +void MMRest::resetProperty(Pid propertyId) +{ + setProperty(propertyId, propertyDefault(propertyId)); + return; +} + +//--------------------------------------------------------- +// getPropertyStyle +//--------------------------------------------------------- + +Sid MMRest::getPropertyStyle(Pid propertyId) const +{ + if (propertyId == Pid::MMREST_NUMBER_POS) { + return Sid::mmRestNumberPos; + } + return Rest::getPropertyStyle(propertyId); +} + +//--------------------------------------------------------- +// getProperty +//--------------------------------------------------------- + +QVariant MMRest::getProperty(Pid propertyId) const +{ + switch (propertyId) { + case Pid::MMREST_NUMBER_POS: + return _mmRestNumberPos; + default: + return Rest::getProperty(propertyId); + } +} + +//--------------------------------------------------------- +// setProperty +//--------------------------------------------------------- + +bool MMRest::setProperty(Pid propertyId, const QVariant& v) +{ + switch (propertyId) { + case Pid::MMREST_NUMBER_POS: + _mmRestNumberPos = v.toDouble(); + triggerLayout(); + break; + default: + return Rest::setProperty(propertyId, v); + } + return true; +} + +//--------------------------------------------------------- +// shape +//--------------------------------------------------------- + +Shape MMRest::shape() const +{ + Shape shape; + shape.add(Rest::shape()); + + qreal _spatium = spatium(); + shape.add(QRectF(0.0, -_spatium, _mmWidth, 2.0 * _spatium)); + + int n = measure()->mmRestCount(); + std::vector&& s = toTimeSigString(QString("%1").arg(n)); + + QRectF r = symBbox(s); + qreal y = _mmRestNumberPos * spatium() - staff()->height() * .5; + qreal x = .5 * (_mmWidth - r.width()); + + r.translate(QPointF(x, y)); + shape.add(r); + + return shape; +} +} diff --git a/libmscore/mmrest.h b/libmscore/mmrest.h new file mode 100644 index 0000000000000..b5d455b80d859 --- /dev/null +++ b/libmscore/mmrest.h @@ -0,0 +1,55 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2020 MuseScore BVBA +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 +// as published by the Free Software Foundation and appearing in +// the file LICENCE.GPL +//============================================================================= + +#ifndef __MMREST_H__ +#define __MMREST_H__ + +#include "rest.h" + +namespace Ms { +//--------------------------------------------------------- +// @@ MMRest +/// This class implements a multimeasure rest. +//--------------------------------------------------------- + +class MMRest: public Rest { + qreal _mmWidth; // width of multimeasure rest + qreal _mmRestNumberPos; // vertical position of number of multimeasure rest + Sid getPropertyStyle(Pid) const override; + +public: + MMRest(Score * s = 0); + MMRest(const MMRest&, bool link = false); + ~MMRest() { + } + + ElementType type() const override { return ElementType::MMREST; } + + MMRest* clone() const override { return new MMRest(* this, false); } + Element* linkedClone() override { return new MMRest(* this, true); } + + void draw(QPainter*) const override; + void layout() override; + void layout(qreal width); + qreal mmWidth() const { return _mmWidth; } + + void write(XmlWriter&) const override; + + QVariant propertyDefault(Pid) const override; + void resetProperty(Pid); + bool setProperty(Pid, const QVariant&) override; + QVariant getProperty(Pid) const override; + + Shape shape() const override; +}; +} // namespace Ms +#endif diff --git a/libmscore/navigate.cpp b/libmscore/navigate.cpp index ea44c75b32198..091c936c512d7 100644 --- a/libmscore/navigate.cpp +++ b/libmscore/navigate.cpp @@ -577,6 +577,7 @@ Element* Score::nextElement() switch (e->type()) { case ElementType::NOTE: case ElementType::REST: + case ElementType::MMREST: case ElementType::CHORD: { Element* next = e->nextElement(); if (next) { @@ -711,6 +712,7 @@ Element* Score::prevElement() switch (e->type()) { case ElementType::NOTE: case ElementType::REST: + case ElementType::MMREST: case ElementType::CHORD: { Element* prev = e->prevElement(); if (prev) { @@ -776,7 +778,8 @@ Element* Score::prevElement() } Element* el = startSeg->lastElementOfSegment(startSeg, staffId); if (stEl->type() == ElementType::CHORD || stEl->type() == ElementType::REST - || stEl->type() == ElementType::REPEAT_MEASURE || stEl->type() == ElementType::NOTE) { + || stEl->type() == ElementType::REPEAT_MEASURE || stEl->type() == ElementType::MMREST + || stEl->type() == ElementType::NOTE) { ChordRest* cr = startSeg->cr(stEl->track()); if (cr) { Element* elCr = cr->lastElementBeforeSegment(); diff --git a/libmscore/read114.cpp b/libmscore/read114.cpp index fdcbe18b56780..b92f2f0eb58a4 100644 --- a/libmscore/read114.cpp +++ b/libmscore/read114.cpp @@ -16,6 +16,7 @@ #include "excerpt.h" #include "chord.h" #include "rest.h" +#include "mmrest.h" #include "keysig.h" #include "volta.h" #include "measure.h" @@ -1759,23 +1760,33 @@ static void readMeasure(Measure* m, int staffIdx, XmlReader& e) e.incTick(crticks); } } else if (tag == "Rest") { - Rest* rest = new Rest(m->score()); - rest->setDurationType(TDuration::DurationType::V_MEASURE); - rest->setTicks(m->timesig() / timeStretch); - rest->setTrack(e.track()); - readRest(m, rest, e); - if (!rest->segment()) { - rest->setParent(m->getSegment(SegmentType::ChordRest, e.tick())); - } - segment = rest->segment(); - segment->add(rest); - - if (!rest->ticks().isValid()) { // hack + if (m->isMMRest()) { + MMRest* mmr = new MMRest(m->score()); + mmr->setTrack(e.track()); + mmr->read(e); + segment = m->getSegment(SegmentType::ChordRest, e.tick()); + segment->add(mmr); + lastTick = e.tick(); + e.incTick(mmr->actualTicks()); + } else { + Rest* rest = new Rest(m->score()); + rest->setDurationType(TDuration::DurationType::V_MEASURE); rest->setTicks(m->timesig() / timeStretch); - } + rest->setTrack(e.track()); + readRest(m, rest, e); + if (!rest->segment()) { + rest->setParent(m->getSegment(SegmentType::ChordRest, e.tick())); + } + segment = rest->segment(); + segment->add(rest); - lastTick = e.tick(); - e.incTick(rest->actualTicks()); + if (!rest->ticks().isValid()) { // hack + rest->setTicks(m->timesig() / timeStretch); + } + + lastTick = e.tick(); + e.incTick(rest->actualTicks()); + } } else if (tag == "Breath") { Breath* breath = new Breath(m->score()); breath->setTrack(e.track()); diff --git a/libmscore/read206.cpp b/libmscore/read206.cpp index 39e990891a8a2..8318b94c14c36 100644 --- a/libmscore/read206.cpp +++ b/libmscore/read206.cpp @@ -39,6 +39,7 @@ #include "tie.h" #include "chord.h" #include "rest.h" +#include "mmrest.h" #include "breath.h" #include "repeat.h" #include "utils.h" @@ -2961,21 +2962,31 @@ static void readMeasure(Measure* m, int staffIdx, XmlReader& e) e.incTick(crticks); } } else if (tag == "Rest") { - Rest* rest = new Rest(score); - rest->setDurationType(TDuration::DurationType::V_MEASURE); - rest->setTicks(m->timesig() / timeStretch); - rest->setTrack(e.track()); - segment = m->getSegment(SegmentType::ChordRest, e.tick()); - rest->setParent(segment); - readRest(rest, e); - segment->add(rest); - - if (!rest->ticks().isValid()) { // hack + if (m->isMMRest()) { + MMRest* mmr = new MMRest(score); + mmr->setTrack(e.track()); + mmr->read(e); + segment = m->getSegment(SegmentType::ChordRest, e.tick()); + segment->add(mmr); + lastTick = e.tick(); + e.incTick(mmr->actualTicks()); + } else { + Rest* rest = new Rest(score); + rest->setDurationType(TDuration::DurationType::V_MEASURE); rest->setTicks(m->timesig() / timeStretch); - } + rest->setTrack(e.track()); + segment = m->getSegment(SegmentType::ChordRest, e.tick()); + rest->setParent(segment); + readRest(rest, e); + segment->add(rest); + + if (!rest->ticks().isValid()) { // hack + rest->setTicks(m->timesig() / timeStretch); + } - lastTick = e.tick(); - e.incTick(rest->actualTicks()); + lastTick = e.tick(); + e.incTick(rest->actualTicks()); + } } else if (tag == "Breath") { Breath* breath = new Breath(score); breath->setTrack(e.track()); diff --git a/libmscore/rest.cpp b/libmscore/rest.cpp index 74404f182eb47..d1b0d92c808a4 100644 --- a/libmscore/rest.cpp +++ b/libmscore/rest.cpp @@ -31,14 +31,6 @@ #include "image.h" namespace Ms { -//--------------------------------------------------------- -// restStyle -//--------------------------------------------------------- - -static const ElementStyle restStyle { - { Sid::mmRestNumberPos, Pid::MMREST_NUMBER_POS }, -}; - //--------------------------------------------------------- // Rest //-------------------------------------------------------- @@ -46,27 +38,19 @@ static const ElementStyle restStyle { Rest::Rest(Score* s) : ChordRest(s) { - _mmWidth = 0; _beamMode = Beam::Mode::NONE; _sym = SymId::restQuarter; - if (score()) { - initElementStyle(&restStyle); - } } Rest::Rest(Score* s, const TDuration& d) : ChordRest(s) { - _mmWidth = 0; _beamMode = Beam::Mode::NONE; _sym = SymId::restQuarter; setDurationType(d); if (d.fraction().isValid()) { setTicks(d.fraction()); } - if (score()) { - initElementStyle(&restStyle); - } } Rest::Rest(const Rest& r, bool link) @@ -79,69 +63,39 @@ Rest::Rest(const Rest& r, bool link) _gap = r._gap; _sym = r._sym; dotline = r.dotline; - _mmWidth = r._mmWidth; for (NoteDot* dot : r._dots) { add(new NoteDot(*dot)); } } +//--------------------------------------------------------- +// Rest::shouldNotBeDrawn +// in tab staff, do not draw rests (except mmrests) +// if rests are off OR if dur. symbols are on +//--------------------------------------------------------- + +bool Rest::shouldNotBeDrawn() const +{ + const StaffType* st = staff() ? staff()->staffTypeForElement(this) : nullptr; + if (generated() + || (st && st->isTabStaff() && (!st->showRests() || st->genDurations()) + && (!measure() || !measure()->isMMRest()))) { + return true; + } + return false; +} + //--------------------------------------------------------- // Rest::draw //--------------------------------------------------------- void Rest::draw(QPainter* painter) const { - const StaffType* stt = staff() ? staff()->staffTypeForElement(this) : nullptr; - if ( - (stt && stt->isTabStaff() - // in tab staff, do not draw rests is rests are off OR if dur. symbols are on - && (!stt->showRests() || stt->genDurations()) - && (!measure() || !measure()->isMMRest())) // show multi measure rest always - || generated() - ) { + if (shouldNotBeDrawn()) { return; } - qreal _spatium = spatium(); - painter->setPen(curColor()); - - if (measure() && measure()->isMMRest()) { - //only on voice 1 - if (track() % VOICES) { - return; - } - - // draw number - int n = measure()->mmRestCount(); - std::vector&& s = toTimeSigString(QString("%1").arg(n)); - qreal y = _mmRestNumberPos * spatium() - staff()->height() * .5; - qreal x = (_mmWidth - symBbox(s).width()) * .5; - drawSymbols(s, painter, QPointF(x, y)); - - // draw horizontal line - qreal pw = _spatium * .7; - QPen pen(painter->pen()); - pen.setWidthF(pw); - painter->setPen(pen); - qreal x1 = pw * .5; - qreal x2 = _mmWidth - x1; - if (_mmRestNumberPos > 0.7 && _mmRestNumberPos < 3.3) { // hack for when number encounters horizontal line - qreal gapDistance = symBbox(s).width() * .5 + _spatium; - qreal midpoint = (x1 + x2) * .5; - painter->drawLine(QLineF(x1, 0.0, midpoint - gapDistance, 0.0)); - painter->drawLine(QLineF(midpoint + gapDistance, 0.0, x2, 0.0)); - } else { - painter->drawLine(QLineF(x1, 0.0, x2, 0.0)); - } - - // draw vertical lines - pen.setWidthF(_spatium * .2); - painter->setPen(pen); - painter->drawLine(QLineF(0.0, -_spatium, 0.0, _spatium)); - painter->drawLine(QLineF(_mmWidth, -_spatium, _mmWidth, _spatium)); - } else { - drawSymbol(_sym, painter); - } + drawSymbol(_sym, painter); } //--------------------------------------------------------- @@ -341,26 +295,6 @@ SymId Rest::getSymbol(TDuration::DurationType type, int line, int lines, int* yo } } -//--------------------------------------------------------- -// layoutMMRest -//--------------------------------------------------------- - -void Rest::layoutMMRest(qreal val) -{ -// static const qreal verticalLineWidth = .2; - - qreal _spatium = spatium(); - _mmWidth = val; -// qreal h = _spatium * (2 + verticalLineWidth); -// qreal w = _mmWidth + _spatium * verticalLineWidth * .5; -// bbox().setRect(-_spatium * verticalLineWidth * .5, -h * .5, w, h); - bbox().setRect(0.0, -_spatium, _mmWidth, _spatium * 2); - - // text -// qreal y = -_spatium * 2.5 - staff()->height() *.5; -// addbbox(QRectF(0, y, w, _spatium * 2)); // approximation -} - //--------------------------------------------------------- // layout //--------------------------------------------------------- @@ -374,11 +308,6 @@ void Rest::layout() e->layout(); } qreal _spatium = spatium(); - if (measure() && measure()->isMMRest()) { - _mmWidth = score()->styleP(Sid::minMMRestWidth) * mag(); - // setbbox(QRectF(0.0, -_spatium, _mmWidth, 2.0 * _spatium)); - return; - } rxpos() = 0.0; const StaffType* stt = staffType(); @@ -895,7 +824,7 @@ void Rest::remove(Element* e) } } -//-------------------------------------------------- +//--------------------------------------------------------- // Rest::write //--------------------------------------------------------- @@ -980,16 +909,14 @@ QVariant Rest::propertyDefault(Pid propertyId) const switch (propertyId) { case Pid::GAP: return false; - case Pid::MMREST_NUMBER_POS: - return score()->styleV(Sid::mmRestNumberPos); default: return ChordRest::propertyDefault(propertyId); } } -//———————————————————————————— +//--------------------------------------------------------- // resetProperty -//———————————————————————————— +//--------------------------------------------------------- void Rest::resetProperty(Pid id) { @@ -997,15 +924,11 @@ void Rest::resetProperty(Pid id) return; } -//———————————————————————————— +//--------------------------------------------------------- // getPropertyStyle -//———————————————————————————— - +//--------------------------------------------------------- Sid Rest::getPropertyStyle(Pid pid) const { - if (pid == Pid::MMREST_NUMBER_POS) { - return Sid::mmRestNumberPos; - } return ChordRest::getPropertyStyle(pid); } @@ -1018,8 +941,6 @@ QVariant Rest::getProperty(Pid propertyId) const switch (propertyId) { case Pid::GAP: return _gap; - case Pid::MMREST_NUMBER_POS: - return _mmRestNumberPos; default: return ChordRest::getProperty(propertyId); } @@ -1050,10 +971,6 @@ bool Rest::setProperty(Pid propertyId, const QVariant& v) } triggerLayout(); break; - case Pid::MMREST_NUMBER_POS: - _mmRestNumberPos = v.toDouble(); - triggerLayout(); - break; default: return ChordRest::setProperty(propertyId, v); } @@ -1098,20 +1015,6 @@ Shape Rest::shape() const Shape shape; if (!_gap) { shape.add(ChordRest::shape()); - if (measure() && measure()->isMMRest()) { - qreal _spatium = spatium(); - shape.add(QRectF(0.0, -_spatium, _mmWidth, 2.0 * _spatium)); - - int n = measure()->mmRestCount(); - std::vector&& s = toTimeSigString(QString("%1").arg(n)); - - QRectF r = symBbox(s); - qreal y = _mmRestNumberPos * spatium() - staff()->height() * .5; - qreal x = .5 * (_mmWidth - r.width()); - - r.translate(QPointF(x, y)); - shape.add(r); - } else #ifndef NDEBUG { shape.add(bbox(), name()); diff --git a/libmscore/rest.h b/libmscore/rest.h index f8e9e084f1d98..d4a3ffc43ac77 100644 --- a/libmscore/rest.h +++ b/libmscore/rest.h @@ -30,8 +30,6 @@ class Rest : public ChordRest // values calculated by layout: SymId _sym; int dotline { -1 }; // depends on rest symbol - qreal _mmWidth; // width of multimeasure rest - qreal _mmRestNumberPos; // vertical position of number of multimeasure rest bool _gap { false }; // invisible and not selectable for user std::vector _dots; @@ -39,7 +37,10 @@ class Rest : public ChordRest qreal upPos() const override; qreal downPos() const override; void setOffset(const QPointF& o) override; + +protected: Sid getPropertyStyle(Pid pid) const override; + bool shouldNotBeDrawn() const; public: Rest(Score* s = 0); @@ -54,6 +55,7 @@ class Rest : public ChordRest Element* linkedClone() override { return new Rest(*this, true); } Measure* measure() const override { return parent() ? toMeasure(parent()->parent()) : 0; } qreal mag() const override; + void draw(QPainter*) const override; void scanElements(void* data, void (* func)(void*, Element*), bool all = true) override; void setTrack(int val); @@ -73,8 +75,6 @@ class Rest : public ChordRest void read(XmlReader&) override; void write(XmlWriter& xml) const override; - void layoutMMRest(qreal val); - qreal mmWidth() const { return _mmWidth; } SymId getSymbol(TDuration::DurationType type, int line, int lines, int* yoffset); void checkDots(); diff --git a/libmscore/score.cpp b/libmscore/score.cpp index dba9ca45fbf9f..735e064b37b27 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -1600,6 +1600,7 @@ void Score::removeElement(Element* element) case ElementType::CHORD: case ElementType::REST: + case ElementType::MMREST: { ChordRest* cr = toChordRest(element); if (cr->beam()) { @@ -2993,7 +2994,7 @@ void Score::padToggle(Pad n, const EditData& ed) } // on measure rest, select the first actual rest - if (cr && cr->isRest() && cr->measure()->isMMRest()) { + if (cr && cr->isMMRest()) { Measure* m = cr->measure()->mmRestFirst(); if (m) { cr = m->findChordRest(m->tick(), 0); @@ -3019,7 +3020,7 @@ void Score::padToggle(Pad n, const EditData& ed) if (!cr) { continue; } - if (cr->isRepeatMeasure() || (cr->isRest() && toRest(cr)->measure() && toRest(cr)->measure()->isMMRest())) { + if (cr->isRepeatMeasure() || cr->isMMRest()) { canAdjustLength = false; break; } @@ -3255,7 +3256,7 @@ void Score::selectRange(Element* e, int staffIdx) activeTrack = cr->track(); } else if (_selection.isSingle()) { Element* oe = _selection.element(); - if (oe && (oe->isNote() || oe->isRest())) { + if (oe && (oe->isNote() || oe->isRest() || oe->isMMRest())) { if (oe->isNote()) { oe = oe->parent(); } diff --git a/libmscore/scoreElement.cpp b/libmscore/scoreElement.cpp index fcdd9ee3f68a2..20974b1cad14e 100644 --- a/libmscore/scoreElement.cpp +++ b/libmscore/scoreElement.cpp @@ -52,6 +52,7 @@ static const ElementName elementNames[] = { { ElementType::AMBITUS, "Ambitus", QT_TRANSLATE_NOOP("elementName", "Ambitus") }, { ElementType::TIMESIG, "TimeSig", QT_TRANSLATE_NOOP("elementName", "Time Signature") }, { ElementType::REST, "Rest", QT_TRANSLATE_NOOP("elementName", "Rest") }, + { ElementType::MMREST, "MMRest", QT_TRANSLATE_NOOP("elementName", "Multimeasure Rest") }, { ElementType::BREATH, "Breath", QT_TRANSLATE_NOOP("elementName", "Breath") }, { ElementType::REPEAT_MEASURE, "RepeatMeasure", QT_TRANSLATE_NOOP("elementName", "Repeat Measure") }, { ElementType::TIE, "Tie", QT_TRANSLATE_NOOP("elementName", "Tie") }, diff --git a/libmscore/scoreElement.h b/libmscore/scoreElement.h index 7c6bd3d90b370..db1ffbf91366b 100644 --- a/libmscore/scoreElement.h +++ b/libmscore/scoreElement.h @@ -57,6 +57,7 @@ class Ottava; class Note; class Chord; class Rest; +class MMRest; class LayoutBreak; class Tremolo; class System; @@ -262,6 +263,7 @@ class ScoreElement CONVERT(Note, NOTE) CONVERT(Rest, REST) + CONVERT(MMRest, MMREST) CONVERT(Chord, CHORD) CONVERT(BarLine, BAR_LINE) CONVERT(Articulation, ARTICULATION) @@ -358,7 +360,7 @@ class ScoreElement #undef CONVERT virtual bool isElement() const { return false; } // overridden in element.h - bool isChordRest() const { return isRest() || isChord() || isRepeatMeasure(); } + bool isChordRest() const { return isRest() || isChord() || isRepeatMeasure() || isMMRest(); } bool isDurationElement() const { return isChordRest() || isTuplet(); } bool isSlurTieSegment() const { return isSlurSegment() || isTieSegment(); } bool isSLineSegment() const; @@ -440,40 +442,42 @@ class ScoreElement static inline ChordRest* toChordRest(ScoreElement* e) { Q_ASSERT(e == 0 || e->type() == ElementType::CHORD || e->type() == ElementType::REST - || e->type() == ElementType::REPEAT_MEASURE); + || e->type() == ElementType::MMREST || e->type() == ElementType::REPEAT_MEASURE); return (ChordRest*)e; } static inline const ChordRest* toChordRest(const ScoreElement* e) { Q_ASSERT(e == 0 || e->type() == ElementType::CHORD || e->type() == ElementType::REST - || e->type() == ElementType::REPEAT_MEASURE); + || e->type() == ElementType::MMREST || e->type() == ElementType::REPEAT_MEASURE); return (const ChordRest*)e; } static inline DurationElement* toDurationElement(ScoreElement* e) { Q_ASSERT(e == 0 || e->type() == ElementType::CHORD || e->type() == ElementType::REST - || e->type() == ElementType::REPEAT_MEASURE || e->type() == ElementType::TUPLET); + || e->type() == ElementType::MMREST || e->type() == ElementType::REPEAT_MEASURE + || e->type() == ElementType::TUPLET); return (DurationElement*)e; } static inline const DurationElement* toDurationElement(const ScoreElement* e) { Q_ASSERT(e == 0 || e->type() == ElementType::CHORD || e->type() == ElementType::REST - || e->type() == ElementType::REPEAT_MEASURE || e->type() == ElementType::TUPLET); + || e->type() == ElementType::MMREST || e->type() == ElementType::REPEAT_MEASURE + || e->type() == ElementType::TUPLET); return (const DurationElement*)e; } static inline Rest* toRest(ScoreElement* e) { - Q_ASSERT(!e || e->isRest() || e->isRepeatMeasure()); + Q_ASSERT(!e || e->isRest() || e->isMMRest() || e->isRepeatMeasure()); return (Rest*)e; } static inline const Rest* toRest(const ScoreElement* e) { - Q_ASSERT(!e || e->isRest() || e->isRepeatMeasure()); + Q_ASSERT(!e || e->isRest() || e->isMMRest() || e->isRepeatMeasure()); return (const Rest*)e; } @@ -613,6 +617,7 @@ CONVERT(HairpinSegment) CONVERT(Bend) CONVERT(TremoloBar) CONVERT(RepeatMeasure) +CONVERT(MMRest) CONVERT(Tuplet) CONVERT(NoteDot) CONVERT(Dynamic) diff --git a/libmscore/segment.cpp b/libmscore/segment.cpp index 9c685d0c86e95..a104653987d2e 100644 --- a/libmscore/segment.cpp +++ b/libmscore/segment.cpp @@ -596,6 +596,7 @@ void Segment::add(Element* el) case ElementType::CHORD: case ElementType::REST: + case ElementType::MMREST: Q_ASSERT(_segmentType == SegmentType::ChordRest); { if (track % VOICES) { @@ -686,6 +687,7 @@ void Segment::remove(Element* el) } break; + case ElementType::MMREST: case ElementType::REPEAT_MEASURE: _elist[track] = 0; break; @@ -772,6 +774,7 @@ SegmentType Segment::segmentType(ElementType type) switch (type) { case ElementType::CHORD: case ElementType::REST: + case ElementType::MMREST: case ElementType::REPEAT_MEASURE: case ElementType::JUMP: case ElementType::MARKER: @@ -1864,7 +1867,7 @@ Element* Segment::prevElement(int activeStaff) return nullptr; } if (el->type() == ElementType::CHORD || el->type() == ElementType::REST - || el->type() == ElementType::REPEAT_MEASURE) { + || el->type() == ElementType::MMREST || el->type() == ElementType::REPEAT_MEASURE) { ChordRest* cr = this->cr(el->track()); if (cr) { Element* elCr = cr->lastElementBeforeSegment(); @@ -1907,7 +1910,7 @@ Element* Segment::prevElement(int activeStaff) Element* prev = seg->prevElementOfSegment(seg, el, activeStaff); if (prev) { if (prev->type() == ElementType::CHORD || prev->type() == ElementType::REST - || prev->type() == ElementType::REPEAT_MEASURE) { + || prev->type() == ElementType::MMREST || prev->type() == ElementType::REPEAT_MEASURE) { ChordRest* cr = seg->cr(prev->track()); if (cr) { Element* elCr = cr->lastElementBeforeSegment(); @@ -1969,8 +1972,8 @@ Element* Segment::prevElement(int activeStaff) return next; } } - if (prev->type() == ElementType::CHORD || prev->type() == ElementType::REST - || prev->type() == ElementType::REPEAT_MEASURE || prev->type() == ElementType::NOTE) { + if (prev->type() == ElementType::CHORD || prev->type() == ElementType::NOTE || prev->type() == ElementType::REST + || prev->type() == ElementType::MMREST || prev->type() == ElementType::REPEAT_MEASURE) { ChordRest* cr = prevSeg->cr(prev->track()); if (cr) { Element* elCr = cr->lastElementBeforeSegment(); diff --git a/libmscore/select.cpp b/libmscore/select.cpp index c596a9bf0cf55..7a5e6ef02470d 100644 --- a/libmscore/select.cpp +++ b/libmscore/select.cpp @@ -236,7 +236,7 @@ ChordRest* Selection::firstChordRest(int track) const Element* el = _el[0]; if (el->isNote()) { return toChordRest(el->parent()); - } else if (el->isRest()) { + } else if (el->isChordRest()) { return toChordRest(el); } return 0; @@ -272,7 +272,7 @@ ChordRest* Selection::lastChordRest(int track) const Element* el = _el[0]; if (el && el->isNote()) { return toChordRest(el->parent()); - } else if (el->isChord() || el->isRest() || el->isRepeatMeasure()) { + } else if (el->isChordRest()) { return toChordRest(el); } return 0; @@ -987,6 +987,7 @@ QByteArray Selection::symbolListMimeData() const case ElementType::KEYSIG: case ElementType::TIMESIG: case ElementType::REST: + case ElementType::MMREST: case ElementType::BREATH: case ElementType::GLISSANDO: case ElementType::REPEAT_MEASURE: diff --git a/libmscore/types.h b/libmscore/types.h index 80252c2469738..a03e67a66fcc8 100644 --- a/libmscore/types.h +++ b/libmscore/types.h @@ -58,6 +58,7 @@ enum class ElementType { AMBITUS, TIMESIG, REST, + MMREST, BREATH, REPEAT_MEASURE, TIE, diff --git a/mscore/debugger/debugger.cpp b/mscore/debugger/debugger.cpp index dc43fe2e04d90..58f21ec7217ab 100644 --- a/mscore/debugger/debugger.cpp +++ b/mscore/debugger/debugger.cpp @@ -1388,7 +1388,6 @@ void RestView::setElement(Element* e) rb.sym->setValue(int(rest->sym())); rb.dotline->setValue(rest->getDotline()); - rb.mmWidth->setValue((rest->measure() && rest->measure()->isMMRest()) ? rest->mmWidth() : 0.0); rb.gap->setChecked(rest->isGap()); int dots = rest->dots(); rb.dot1->setEnabled(dots > 0); diff --git a/mscore/debugger/rest.ui b/mscore/debugger/rest.ui index 726d2d0b89cdc..ffdcee697d046 100644 --- a/mscore/debugger/rest.ui +++ b/mscore/debugger/rest.ui @@ -81,32 +81,6 @@ - - - - mmWidth - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 5 - - - - - - - true - - - QAbstractSpinBox::NoButtons - - - 9999.989999999999782 - - - diff --git a/mscore/editstyle.cpp b/mscore/editstyle.cpp index 86a88b970e0dc..855f8a1cac681 100644 --- a/mscore/editstyle.cpp +++ b/mscore/editstyle.cpp @@ -716,7 +716,8 @@ const std::map EditStyle::PAGES = { { ElementType::CLEF, &EditStyle::PageClefs }, { ElementType::KEYSIG, &EditStyle::PageAccidentals }, { ElementType::MEASURE, &EditStyle::PageMeasure }, - { ElementType::REST, &EditStyle::PageMeasure }, + { ElementType::REST, &EditStyle::PageRests }, + { ElementType::MMREST, &EditStyle::PageRests }, { ElementType::BAR_LINE, &EditStyle::PageBarlines }, { ElementType::NOTE, &EditStyle::PageNotes }, { ElementType::CHORD, &EditStyle::PageNotes }, diff --git a/mscore/editstyle.ui b/mscore/editstyle.ui index 8fa5b127a313e..ddb2726245c90 100644 --- a/mscore/editstyle.ui +++ b/mscore/editstyle.ui @@ -81,6 +81,11 @@ Measure Numbers + + + Rests + + System @@ -247,7 +252,7 @@ - 4 + 1 @@ -376,135 +381,6 @@ - - - - Create multimeasure rests - - - true - - - false - - - - - - - - 1 - - - 2 - - - - - - - sp - - - 2.000000000000000 - - - 4.000000000000000 - - - - - - - Reset to default - - - Reset 'Minimum width of measure' value - - - - - - - :/data/icons/edit-reset.svg:/data/icons/edit-reset.svg - - - - - - - Minimum number of empty measures: - - - minEmptyMeasures - - - - - - - Minimum width of measure: - - - minMeasureWidth - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Vertical position of number: - - - - - - - sp - - - -99.989999999999995 - - - 0.500000000000000 - - - - - - - Reset to default - - - Reset 'Vertical position of number' value - - - - - - - :/data/icons/edit-reset.svg:/data/icons/edit-reset.svg - - - - - - - - @@ -2221,6 +2097,188 @@ + + + + + + Multimeasure Rests + + + true + + + false + + + + + + Minimum number of empty measures: + + + minEmptyMeasures + + + + + + + Reset to default + + + Reset 'Minimum width of measure' value + + + + + + + :/data/icons/edit-reset.svg:/data/icons/edit-reset.svg + + + + + + + Minimum width of measure: + + + minMeasureWidth + + + + + + + sp + + + 2.000000000000000 + + + 4.000000000000000 + + + + + + + 1 + + + 2 + + + + + + + Vertical position of number: + + + + + + + sp + + + -99.989999999999995 + + + 0.500000000000000 + + + + + + + Reset to default + + + Reset 'Vertical position of number' value + + + + + + + :/data/icons/edit-reset.svg:/data/icons/edit-reset.svg + + + + + + + Margin between H-bar and barlines: + + + + + + + + 0 + 0 + + + + sp + + + 0.100000000000000 + + + + + + + Reset to default + + + Reset 'Multimeasure rest margin' value + + + + + + + :/data/icons/edit-reset.svg:/data/icons/edit-reset.svg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 394fe6c3447f4..50fd2e7e3fd2f 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -56,6 +56,7 @@ #include "libmscore/lasso.h" #include "libmscore/lyrics.h" #include "libmscore/measure.h" +#include "libmscore/mmrest.h" #include "libmscore/navigate.h" #include "libmscore/notedot.h" #include "libmscore/note.h" @@ -3087,7 +3088,7 @@ void ScoreView::startNoteEntry() el = _score->selection().firstChordRest(); } if (el == 0 - || (el->type() != ElementType::CHORD && el->type() != ElementType::REST && el->type() != ElementType::NOTE)) { + || (el->type() != ElementType::CHORD && el->type() != ElementType::REST && el->type() != ElementType::MMREST && el->type() != ElementType::NOTE)) { // if no note/rest is selected, start with voice 0 int track = is.track() == -1 ? 0 : (is.track() / VOICES) * VOICES; // try to find an appropriate measure to start in @@ -3648,6 +3649,8 @@ void ScoreView::adjustCanvasPosition(const Element* el, bool playBack, int staff m = static_cast(el)->chord()->measure(); } else if (el->type() == ElementType::REST) { m = static_cast(el)->measure(); + } else if (el->type() == ElementType::MMREST) { + m = static_cast(el)->measure(); } else if (el->type() == ElementType::CHORD) { m = static_cast(el)->measure(); } else if (el->type() == ElementType::SEGMENT) { diff --git a/mtest/scripting/p1.log.ref b/mtest/scripting/p1.log.ref index 58462a717b1c8..99a818cac5c90 100644 --- a/mtest/scripting/p1.log.ref +++ b/mtest/scripting/p1.log.ref @@ -2,13 +2,13 @@ test script p1: read score elements found:Clef (20) at 0 found:KeySig (21) at 0 found:TimeSig (23) at 0 -found:Chord (92) at 0 +found:Chord (93) at 0 beamMode:0 small:false stemDirection:AUTO duration:1/4 found:Rest (24) at 480 -found:Chord (92) at 960 +found:Chord (93) at 960 beamMode:0 small:false stemDirection:AUTO