Skip to content

Commit

Permalink
Merge pull request #1821 from mgavioli/Fix_48721_glissando_cloning
Browse files Browse the repository at this point in the history
Fix #48721 - Glissando cloning
  • Loading branch information
lasconic committed Mar 5, 2015
2 parents 574ae7a + 65973bb commit 8c06c3a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 43 deletions.
46 changes: 4 additions & 42 deletions libmscore/excerpt.cpp
Expand Up @@ -448,29 +448,10 @@ void cloneStaves(Score* oscore, Score* score, const QList<int>& map)
// makes sure the 'other' spanner anchor element is already set up)
// 'on' is the old spanner end note and 'nn' is the new spanner end note
for (Spanner* oldSp : on->spannerBack()) {
// determining the new spanner start element:
Note* oldStart = static_cast<Note*>(oldSp->startElement());
Note* newStart = nullptr;
// determine the track offset from the spanner end to the spanner start
int newTrack = nn->track() + (on->track() - oldStart->track());
// look in notes linked to oldStart for a note with the same
// score as new score and required track offset
for (ScoreElement* newEl : oldStart->linkList())
if (static_cast<Note*>(newEl)->score() == score
&& static_cast<Note*>(newEl)->track() == newTrack) {
newStart = static_cast<Note*>(newEl);
break;
}
Note* newStart = Spanner::startElementFromSpanner(oldSp, nn);
if (newStart != nullptr) {
Spanner* newSp = static_cast<Spanner*>(oldSp->linkedClone());
newSp->setScore(score);
newSp->setParent(newStart);
newSp->setStartElement(newStart);
newSp->setEndElement(nn);
newSp->setTick(newStart->chord()->tick());
newSp->setTick2(nch->tick());
newSp->setTrack(newTrack);
newSp->setTrack2(nn->track());
newSp->setNoteSpan(newStart, nn);
score->addElement(newSp);
}
else {
Expand Down Expand Up @@ -724,29 +705,10 @@ void cloneStaff(Staff* srcStaff, Staff* dstStaff)
// makes sure the 'other' spanner anchor element is already set up)
// 'on' is the old spanner end note and 'nn' is the new spanner end note
for (Spanner* oldSp : on->spannerBack()) {
// determining the new spanner start element:
Note* oldStart = static_cast<Note*>(oldSp->startElement());
Note* newStart = nullptr;
// determine the track offset from the spanner end to the spanner start
int newTrack = nn->track() + (on->track() - oldStart->track());
// look in notes linked to oldStart for a note with the same
// score as new score and required track offset
for (ScoreElement* newEl : oldStart->linkList())
if (static_cast<Note*>(newEl)->score() == score
&& static_cast<Note*>(newEl)->track() == newTrack) {
newStart = static_cast<Note*>(newEl);
break;
}
Note* newStart = Spanner::startElementFromSpanner(oldSp, nn);
if (newStart != nullptr) {
Spanner* newSp = static_cast<Spanner*>(oldSp->linkedClone());
newSp->setScore(score);
newSp->setParent(newStart);
newSp->setStartElement(newStart);
newSp->setEndElement(nn);
newSp->setTick(newStart->chord()->tick());
newSp->setTick2(nch->tick());
newSp->setTrack(newTrack);
newSp->setTrack2(nn->track());
newSp->setNoteSpan(newStart, nn);
score->addElement(newSp);
}
else {
Expand Down
87 changes: 87 additions & 0 deletions libmscore/spanner.cpp
Expand Up @@ -483,6 +483,93 @@ void Spanner::computeEndElement()
}
}

//---------------------------------------------------------
// startElementFromSpanner
//
// Given a Spanner and an end element, determines a start element suitable for the end
// element of a new Spanner, so that it is 'parallel' to the old one.
// Can be used while cloning a linked Spanner, to update the cloned spanner start and end elements
// (Spanner(const Spanner&) copies start and end elements from the original to the copy).
// NOTES: Only spanners with Anchor::NOTE are currently supported.
// Going back from end to start ensures the 'other' anchor of this is already set up
// (for instance, while cloning staves)
//---------------------------------------------------------

Note* Spanner::startElementFromSpanner(Spanner* sp, Element* newEnd)
{
if (sp->anchor() != Anchor::NOTE)
return nullptr;

Note* oldStart = static_cast<Note*>(sp->startElement());
Note* oldEnd = static_cast<Note*>(sp->endElement());
Note* newStart = nullptr;
Score* score = newEnd->score();
// determine the track where to expect the 'parallel' start element
int newTrack = newEnd->track() + (oldEnd->track() - oldStart->track());
// look in notes linked to oldStart for a note with the
// same score as new score and appropriate track
for (ScoreElement* newEl : oldStart->linkList())
if (static_cast<Note*>(newEl)->score() == score
&& static_cast<Note*>(newEl)->track() == newTrack) {
newStart = static_cast<Note*>(newEl);
break;
}
return newStart;
}

//---------------------------------------------------------
// endElementFromSpanner
//
// Given a Spanner and a start element, determines an end element suitable for the start
// element of a new Spanner, so that it is 'parallel' to the old one.
// Can be used while cloning a linked Spanner, to update the cloned spanner start and end elements
// (Spanner(const Spanner&) copies start and end elements from the original to the copy).
// NOTES: Only spanners with Anchor::NOTE are currently supported.
//---------------------------------------------------------

Note* Spanner::endElementFromSpanner(Spanner* sp, Element* newStart)
{
if (sp->anchor() != Anchor::NOTE)
return nullptr;

Note* oldStart = static_cast<Note*>(sp->startElement());
Note* oldEnd = static_cast<Note*>(sp->endElement());
Note* newEnd = nullptr;
Score* score = newStart->score();
// determine the track where to expect the 'parallel' start element
int newTrack = newStart->track() + (oldEnd->track() - oldStart->track());
// look in notes linked to oldEnd for a note with the
// same score as new score and appropriate track
for (ScoreElement* newEl : oldEnd->linkList())
if (static_cast<Note*>(newEl)->score() == score
&& static_cast<Note*>(newEl)->track() == newTrack) {
newEnd = static_cast<Note*>(newEl);
break;
}
return newEnd;
}

//---------------------------------------------------------
// setNoteSpan
//
// Sets up all the variables congruent with given start and end note anchors.
//---------------------------------------------------------

void Spanner::setNoteSpan(Note* startNote, Note* endNote)
{
if (_anchor != Anchor::NOTE)
return;

setScore(startNote->score());
setParent(startNote);
setStartElement(startNote);
setEndElement(endNote);
setTick(startNote->chord()->tick());
setTick2(endNote->chord()->tick());
setTrack(startNote->track());
setTrack2(endNote->track());
}

//---------------------------------------------------------
// startChord
//---------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions libmscore/spanner.h
Expand Up @@ -22,6 +22,7 @@ class Spanner;
class System;
class Chord;
class ChordRest;
class Note;

//---------------------------------------------------------
// SpannerSegmentType
Expand Down Expand Up @@ -164,6 +165,9 @@ class Spanner : public Element {

void computeStartElement();
void computeEndElement();
static Note* endElementFromSpanner(Spanner* sp, Element* newStart);
static Note* startElementFromSpanner(Spanner* sp, Element* newEnd);
void setNoteSpan(Note* startNote, Note* endNote);

Element* startElement() const { return _startElement; }
Element* endElement() const { return _endElement; }
Expand Down
18 changes: 17 additions & 1 deletion libmscore/undo.cpp
Expand Up @@ -74,6 +74,7 @@
#include "sym.h"
#include "utils.h"
#include "stringdata.h"
#include "glissando.h"

namespace Ms {

Expand Down Expand Up @@ -946,7 +947,22 @@ void Score::undoAddElement(Element* element)
}
foreach (ScoreElement* ee, *links) {
Element* e = static_cast<Element*>(ee);
Element* ne = (e == parent) ? element : element->linkedClone();
Element* ne;
if (e == parent)
ne = element;
else {
if (element->type() == Element::Type::GLISSANDO) { // and other spanners with Anchor::NOTE
Note* newEnd = Spanner::endElementFromSpanner(static_cast<Glissando*>(element), e);
if (newEnd) {
ne = element->linkedClone();
static_cast<Spanner*>(ne)->setNoteSpan(static_cast<Note*>(e), newEnd);
}
else //couldn't find suitable start note
continue;
}
else
ne = element->linkedClone();
}
ne->setScore(e->score());
ne->setSelected(false);
ne->setParent(e);
Expand Down

0 comments on commit 8c06c3a

Please sign in to comment.