diff --git a/libmscore/clef.cpp b/libmscore/clef.cpp index 9ac6ac8c4085..adefca56db1a 100644 --- a/libmscore/clef.cpp +++ b/libmscore/clef.cpp @@ -148,10 +148,13 @@ void Clef::layout() int lines = 5; // assume a resonable default qreal lineDist = 1.0; - StaffType* staffType; - if (staff() && staff()->staffType()) { + Staff* stf = staff(); + StaffType* staffType = nullptr; + if (stf && stf->staffType()) { staffType = staff()->staffType(); if (!staffType->genClef()) { // if no clef, set empty bbox and do nothing + qDeleteAll(elements); + elements.clear(); setbbox(QRectF()); return; } @@ -163,8 +166,46 @@ void Clef::layout() if (ClefInfo::staffGroup(clefType()) != TAB_STAFF_GROUP) setClefType( ClefType(score()->styleI(ST_tabClef)) ); } - // all staff types: init values from staff type - lines = staffType->lines(); + + // + // all staff types + // + // courtesy clef + // + bool showClef = true; + Segment* clefSeg = static_cast(parent()); + if (clefSeg) { + int tick = clefSeg->tick(); + // only if there is a clef change + if (stf->clef(tick) != stf->clef(tick-1)) { + // locate clef at the begining of next measure, if any + Clef* clefNext = nullptr; + Segment* clefSegNext = nullptr; + Measure* meas = static_cast(clefSeg->parent()); + Measure* measNext = meas->nextMeasure(); + if (measNext) { + clefSegNext = measNext->findSegment(Segment::SegClef, tick); + if (clefSegNext) + clefNext = static_cast(clefSegNext->element(track())); + } + // show this clef if: it is not a courtesy clef (no next clef or not at the end of the measure) + showClef = !clefNext || (clefSeg->tick() != meas->tick() + meas->ticks()) + // if courtesy clef: show if score has courtesy clefs on + || ( score()->styleB(ST_genCourtesyClef) + // AND measure is not at the end of a repeat or of a section + && !( (meas->repeatFlags() & RepeatEnd) || meas->sectionBreak() ) + // AND this clef has courtesy clef turned on + && showCourtesy() ); + if (!showClef) { // if no clef, set empty bbox and do nothing + qDeleteAll(elements); + elements.clear(); + setbbox(QRectF()); + return; + } + } + } + + lines = staffType->lines(); // init values from staff type lineDist = staffType->lineDistance().val(); } diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 88344195817e..a00656334033 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -1959,67 +1959,8 @@ QList Score::layoutSystemRow(qreal rowWidth, bool isFirstSystem, bool u } } - // courtesy clefs - // no courtesy clef if this measure is the end of a repeat + // courtesy clefs: show/hide of courtesy clefs moved to Clef::layout() - bool showCourtesyClef = styleB(ST_genCourtesyClef) && nm && !(m->repeatFlags() & RepeatEnd); - for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) { - Staff* staff = _staves[staffIdx]; - ClefType clefType = staff->clef(tick); - if (clefType == staff->clef(tick-1)) - continue; - - bool show = showCourtesyClef; - Clef* clef; - if (showCourtesyClef) { - // locate a clef in next measure and, if found, - // check if it has court. sig turned off - s = nm->findSegment(Segment::SegClef, tick); - if (s) { - clef = static_cast(s->element(staffIdx*VOICES)); - if (clef && !clef->showCourtesy()) { - show = false; - continue; // this key change has court. sig turned off - } - } - } - s = m->findSegment(Segment::SegClef, tick); - if (s) - clef = static_cast(s->element(staffIdx * VOICES)); - else - clef = 0; - Clef* nextClef = 0; - Segment* ns = nm->findSegment(Segment::SegClef, tick); - if (ns) - nextClef = static_cast(ns->element(staffIdx * VOICES)); - if (clef && !nextClef) { - // - // move original clef to next measure - // - nextClef = clef->clone(); - ns = nm->undoGetSegment(Segment::SegClef, tick); - nextClef->setParent(ns); - undoAddElement(nextClef); - } - if (clef && !show) { - undoRemoveElement(clef); - clef = 0; - } - else if (!clef && show) { - s = m->undoGetSegment(Segment::SegClef, tick); - int track = staffIdx * VOICES; - clef = new Clef(this); - clef->setClefType(clefType); - clef->setTrack(track); - clef->setSmall(true); - clef->setParent(s); - undoAddElement(clef); - } - if (clef) - clef->setGenerated(true); - if (nextClef) - nextClef->setGenerated(false); - } } // diff --git a/libmscore/undo.cpp b/libmscore/undo.cpp index 6b26387344bc..915a576dc19a 100644 --- a/libmscore/undo.cpp +++ b/libmscore/undo.cpp @@ -512,41 +512,42 @@ void Score::undoChangeClef(Staff* ostaff, Segment* seg, ClefType st) continue; } - // move clef to last segment of prev measure? - // TODO: section break? - Segment* segment = measure->findSegment(seg->segmentType(), tick); + Segment* destSeg = measure->findSegment(Segment::SegClef, tick); - if (firstSeg - && measure->prevMeasure() - && !(measure->prevMeasure()->repeatFlags() & RepeatEnd) + // move measure-initial clef to last segment of prev measure + + if (firstSeg // if at start of measure + && measure->prevMeasure() // and there is a previous measure ) { measure = measure->prevMeasure(); - segment = measure->findSegment(seg->segmentType(), tick); - if (!segment && (seg->segmentType() != Segment::SegClef)) - segment = measure->findSegment(Segment::SegClef, tick); + destSeg = measure->findSegment(Segment::SegClef, tick); } - if (segment) { - if (segment->segmentType() != Segment::SegClef) { - if (segment->prev() && segment->prev()->segmentType() == Segment::SegClef) { - segment = segment->prev(); + if (destSeg) { + // if destSeg not a Clef seg... + if (destSeg->segmentType() != Segment::SegClef) { + // ...check prev seg is Clef seg: if yes, prev seg is our dest seg + if (destSeg->prev() && destSeg->prev()->segmentType() == Segment::SegClef) { + destSeg = destSeg->prev(); } + // if no Clef seg (current or previous), create a new Clef seg else { Segment* s = new Segment(measure, Segment::SegClef, seg->tick()); - s->setNext(segment); - s->setPrev(segment->prev()); + s->setNext(destSeg); + s->setPrev(destSeg->prev()); score->undoAddElement(s); - segment = s; + destSeg = s; } } } + // if no dest seg, create a new Clef seg else { - segment = new Segment(measure, Segment::SegClef, seg->tick()); - score->undoAddElement(segment); + destSeg = new Segment(measure, Segment::SegClef, seg->tick()); + score->undoAddElement(destSeg); } int staffIdx = staff->idx(); int track = staffIdx * VOICES; - Clef* clef = static_cast(segment->element(track)); + Clef* clef = static_cast(destSeg->element(track)); if (clef) { // @@ -577,7 +578,7 @@ void Score::undoChangeClef(Staff* ostaff, Segment* seg, ClefType st) clef = new Clef(score); clef->setTrack(track); clef->setClefType(st); - clef->setParent(segment); + clef->setParent(destSeg); score->undo(new AddElement(clef)); } } diff --git a/mscore/inspector/inspector.cpp b/mscore/inspector/inspector.cpp index af64dd08416d..55433bcc96b9 100644 --- a/mscore/inspector/inspector.cpp +++ b/mscore/inspector/inspector.cpp @@ -493,6 +493,48 @@ InspectorClef::InspectorClef(QWidget* parent) mapSignals(); } +// InspectorClef::setElement + +void InspectorClef::setElement() + { + otherClef = nullptr; // no 'other clef' yet + InspectorBase::setElement(); + + // try to locate the 'other clef' of a courtesy / main pair + Clef * clef = static_cast(inspector->element()); + // if not in a clef-segment-measure hierachy, do nothing + if (!clef->parent() || clef->parent()->type() != Element::SEGMENT) + return; + Segment* segm = static_cast(clef->parent()); + int segmTick = segm->tick(); + if (!segm->parent() || segm->parent()->type() != Element::MEASURE) + return; + + Measure* meas = static_cast(segm->parent()); + Measure* otherMeas = nullptr; + Segment* otherSegm = nullptr; + if (segmTick == meas->tick()) // if clef segm is measure-initial + otherMeas = meas->prevMeasure(); // look for a previous measure + else if (segmTick == meas->tick()+meas->ticks()) // if clef segm is measure-final + otherMeas = meas->nextMeasure(); // look for a next measure + // look for a clef segment in the 'other' measure at the same tick of this clef segment + if (otherMeas) + otherSegm = otherMeas->findSegment(Segment::SegClef, segmTick); + // if any 'other' segment found, look for a clef in the same track as this + if (otherSegm) + otherClef = static_cast(otherSegm->element(clef->track())); + } + +// InspectorClef::valueChanged + +void InspectorClef::valueChanged(int idx) + { + // copy into 'other clef' the ShowCouretsy ser of this clef + if (idx == 6 && otherClef) + otherClef->setShowCourtesy(c.showCourtesy->isChecked()); + InspectorBase::valueChanged(idx); + } + //--------------------------------------------------------- // InspectorTempoText //--------------------------------------------------------- diff --git a/mscore/inspector/inspector.h b/mscore/inspector/inspector.h index 910331ab17f9..f802487ae700 100644 --- a/mscore/inspector/inspector.h +++ b/mscore/inspector/inspector.h @@ -130,15 +130,22 @@ class InspectorRest : public InspectorBase { // InspectorClef //--------------------------------------------------------- +class Clef; + class InspectorClef : public InspectorBase { Q_OBJECT UiInspectorElement e; Ui::InspectorSegment s; Ui::InspectorClef c; + Clef* otherClef; // the courtesy clef for a main clef or viceversa + // used to keep in sync ShowCourtesy setting of both clefs + protected slots: + virtual void valueChanged(int idx); public: InspectorClef(QWidget* parent); + virtual void setElement(); }; //--------------------------------------------------------- diff --git a/mtest/libmscore/CMakeLists.txt b/mtest/libmscore/CMakeLists.txt index ccef90a8e93e..76788a25869c 100644 --- a/mtest/libmscore/CMakeLists.txt +++ b/mtest/libmscore/CMakeLists.txt @@ -12,7 +12,7 @@ #============================================================================= subdirs( - beam chordsymbol clef compat concertpitch copypaste copypastesymbollist dynamic element + beam chordsymbol clef clef_courtesy compat concertpitch copypaste copypastesymbollist dynamic element hairpin join keysig layout link measure midi note plugins repeat split splitstaff timesig transpose tuplet ) diff --git a/mtest/libmscore/clef_courtesy/CMakeLists.txt b/mtest/libmscore/clef_courtesy/CMakeLists.txt new file mode 100644 index 000000000000..3efb6fa02fe2 --- /dev/null +++ b/mtest/libmscore/clef_courtesy/CMakeLists.txt @@ -0,0 +1,16 @@ +#============================================================================= +# MuseScore +# Music Composition & Notation +# +# Copyright (C) 2011 Werner Schweer +# +# 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 LICENSE.GPL +#============================================================================= + +set(TARGET tst_clef_courtesy) + +include(${PROJECT_SOURCE_DIR}/mtest/cmake.inc) + diff --git a/mtest/libmscore/clef_courtesy/clef_courtesy01-ref.mscx b/mtest/libmscore/clef_courtesy/clef_courtesy01-ref.mscx new file mode 100644 index 000000000000..cf472c67f5a4 --- /dev/null +++ b/mtest/libmscore/clef_courtesy/clef_courtesy01-ref.mscx @@ -0,0 +1,254 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + 0 + + + Flute + + Flute + 59 + 98 + 60 + 93 + + 100 + 100 + + + 100 + 85 + + + 100 + 100 + + + 120 + 100 + + + + + + + + + + G + G + + + 0 + + + 4 + 4 + 1 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + whole + + 72 + 14 + + + + G8va + G8va + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + section + 2 + + + whole + + 72 + 14 + + + + G + G + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/clef_courtesy/clef_courtesy01.mscx b/mtest/libmscore/clef_courtesy/clef_courtesy01.mscx new file mode 100644 index 000000000000..26b0a5fb6fae --- /dev/null +++ b/mtest/libmscore/clef_courtesy/clef_courtesy01.mscx @@ -0,0 +1,246 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + 0 + + + Flute + + Flute + 59 + 98 + 60 + 93 + + 100 + 100 + + + 100 + 85 + + + 100 + 100 + + + 120 + 100 + + + + + + + + + + G + G + + + 0 + + + 4 + 4 + 1 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + section + 2 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/clef_courtesy/clef_courtesy02-ref.mscx b/mtest/libmscore/clef_courtesy/clef_courtesy02-ref.mscx new file mode 100644 index 000000000000..436404270544 --- /dev/null +++ b/mtest/libmscore/clef_courtesy/clef_courtesy02-ref.mscx @@ -0,0 +1,255 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + 0 + + + Flute + + Flute + 59 + 98 + 60 + 93 + + 100 + 100 + + + 100 + 85 + + + 100 + 100 + + + 120 + 100 + + + + + + + + + + G + G + + + 0 + + + 4 + 4 + 1 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + whole + + 72 + 14 + + + + G8va + G8va + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + section + 2 + + + whole + + 72 + 14 + + + + G + G + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/clef_courtesy/clef_courtesy02.mscx b/mtest/libmscore/clef_courtesy/clef_courtesy02.mscx new file mode 100644 index 000000000000..f726242a5a95 --- /dev/null +++ b/mtest/libmscore/clef_courtesy/clef_courtesy02.mscx @@ -0,0 +1,247 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + 0 + + + Flute + + Flute + 59 + 98 + 60 + 93 + + 100 + 100 + + + 100 + 85 + + + 100 + 100 + + + 120 + 100 + + + + + + + + + + G + G + + + 0 + + + 4 + 4 + 1 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + line + 2 + + + section + 2 + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + normal + 1 + + + + + whole + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/clef_courtesy/tst_clef_courtesy.cpp b/mtest/libmscore/clef_courtesy/tst_clef_courtesy.cpp new file mode 100644 index 000000000000..b994a9f22626 --- /dev/null +++ b/mtest/libmscore/clef_courtesy/tst_clef_courtesy.cpp @@ -0,0 +1,162 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2012 Werner Schweer +// +// 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 +#include "mtest/testutils.h" +#include "libmscore/clef.h" +#include "libmscore/measure.h" +#include "libmscore/score.h" +#include "libmscore/undo.h" + +#define DIR QString("libmscore/clef_courtesy/") + +using namespace Ms; + +//--------------------------------------------------------- +// TestClef +//--------------------------------------------------------- + +class TestClefCourtesy : public QObject, public MTest + { + Q_OBJECT + + private slots: + void initTestCase(); + void clef_courtesy01(); + void clef_courtesy02(); + }; + +//--------------------------------------------------------- +// initTestCase +//--------------------------------------------------------- + +void TestClefCourtesy::initTestCase() + { + initMTest(); + } + +//--------------------------------------------------------- +// clef_courtesy01 +// add two clefs mid-score at the begining of systems and look for courtesy clefs +// the first should be there, the second should not, as it is after a section break +//--------------------------------------------------------- + +void TestClefCourtesy::clef_courtesy01() + { + Score* score = readScore(DIR + "clef_courtesy01.mscx"); + score->doLayout(); + + // 'go' to 4th measure + Measure* m1 = score->firstMeasure(); + for (int i=0; i < 3; i++) + m1 = m1->nextMeasure(); + // make a clef-drop object and drop it to the measure + Clef* clef = new Clef(score); // create a new element, as Measure::drop() will eventually delete it + clef->setClefType(ClefType::G1); + DropData dropData; + dropData.pos = m1->pagePos(); + dropData.element = clef; + m1->drop(dropData); + + // 'go' to 7th measure + Measure* m2 = m1; + for (int i=0; i < 3; i++) + m2 = m2->nextMeasure(); + // make a clef-drop object and drop it to the measure + clef = new Clef(score); // create a new element, as Measure::drop() will eventually delete it + clef->setClefType(ClefType::G); + dropData.pos = m2->pagePos(); + dropData.element = clef; + m2->drop(dropData); + score->doLayout(); + + // check the required courtesy clef is there and it is shown + Clef* clefCourt = nullptr; + Measure* m = m1->prevMeasure(); + Segment* seg = m->findSegment(Segment::SegClef, m1->tick()); + QVERIFY2(seg != nullptr, "No SegClef in measure 3."); + clefCourt = static_cast(seg->element(0)); + QVERIFY2(clefCourt != nullptr, "No courtesy clef element in measure 3."); + QVERIFY2(clefCourt->bbox().width() > 0, "Courtesy clef in measure 3 is hidden."); + + // check the not required courtesy clef element is there but it is not shown + clefCourt = nullptr; + m = m2->prevMeasure(); + seg = m->findSegment(Segment::SegClef, m2->tick()); + QVERIFY2(seg != nullptr, "No SegClef in measure 6."); + clefCourt = static_cast(seg->element(0)); + QVERIFY2(clefCourt != nullptr, "No courtesy clef element in measure 6."); + QVERIFY2(clefCourt->bbox().width() == 0, "Courtesy clef in measure 3 is NOT hidden."); + + QVERIFY(saveCompareScore(score, "clef_courtesy01.mscx", DIR + "clef_courtesy01-ref.mscx")); + delete score; + } + +//--------------------------------------------------------- +// clef_courtesy02 +// add two clefs mid-score at the begining of systems and look for courtesy clefs +// neither should be there, as courtesy clefs are turned off +//--------------------------------------------------------- + +void TestClefCourtesy::clef_courtesy02() + { + Score* score = readScore(DIR + "clef_courtesy02.mscx"); + score->doLayout(); + + // 'go' to 4th measure + Measure* m1 = score->firstMeasure(); + for (int i=0; i < 3; i++) + m1 = m1->nextMeasure(); + // make a clef-drop object and drop it to the measure + Clef* clef = new Clef(score); // create a new element, as Measure::drop() will eventually delete it + clef->setClefType(ClefType::G1); + DropData dropData; + dropData.pos = m1->pagePos(); + dropData.element = clef; + m1->drop(dropData); + + // 'go' to 7th measure + Measure* m2 = m1; + for (int i=0; i < 3; i++) + m2 = m2->nextMeasure(); + // make a clef-drop object and drop it to the measure + clef = new Clef(score); // create a new element, as Measure::drop() will eventually delete it + clef->setClefType(ClefType::G); + dropData.pos = m2->pagePos(); + dropData.element = clef; + m2->drop(dropData); + score->doLayout(); + + // check both clef elements are there, but none is shown + Clef* clefCourt = nullptr; + Measure* m = m1->prevMeasure(); + Segment* seg = m->findSegment(Segment::SegClef, m1->tick()); + QVERIFY2(seg != nullptr, "No SegClef in measure 3."); + clefCourt = static_cast(seg->element(0)); + QVERIFY2(clefCourt != nullptr, "No courtesy clef element in measure 3."); + QVERIFY2(clefCourt->bbox().width() == 0, "Courtesy clef in measure 3 is NOT hidden."); + + clefCourt = nullptr; + m = m2->prevMeasure(); + seg = m->findSegment(Segment::SegClef, m2->tick()); + QVERIFY2(seg != nullptr, "No SegClef in measure 6."); + clefCourt = static_cast(seg->element(0)); + QVERIFY2(clefCourt != nullptr, "No courtesy clef element in measure 6."); + QVERIFY2(clefCourt->bbox().width() == 0, "Courtesy clef in measure 3 is NOT hidden."); + + QVERIFY(saveCompareScore(score, "clef_courtesy02.mscx", DIR + "clef_courtesy02-ref.mscx")); + delete score; + } + +QTEST_MAIN(TestClefCourtesy) +#include "tst_clef_courtesy.moc" +