Skip to content

Commit

Permalink
[Cmd: Paste Clone] insert cloned measure bases via shortcut or right-…
Browse files Browse the repository at this point in the history
…click score menu

Frames work with regular copy paste (as insertion, not appending)
[Keysig/Timesig/Clef] Copied before performing
[Score to score]
V/H/T Boxes to allow copy-drag to clone. Also work as regular copy/paste since they didn't do anything beforehand
  • Loading branch information
worldwideweary committed Sep 17, 2024
1 parent 4f02df4 commit 0c8d8a0
Show file tree
Hide file tree
Showing 14 changed files with 616 additions and 6 deletions.
18 changes: 18 additions & 0 deletions libmscore/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,11 @@ bool Box::acceptDrop(EditData& data) const
case ElementType::STAFF_TEXT:
case ElementType::IMAGE:
case ElementType::SYMBOL:
case ElementType::VBOX:
case ElementType::HBOX:
case ElementType::TBOX:
case ElementType::MEASURE_LIST:
case ElementType::MEASURE:
return true;
case ElementType::ICON:
switch (toIcon(data.dropElement)->iconType()) {
Expand Down Expand Up @@ -587,6 +592,19 @@ Element* Box::drop(EditData& data)
return text;
}

case ElementType::HBOX:
case ElementType::VBOX:
case ElementType::TBOX:
{
if (auto mbSource = e->findMeasureBase()) {
auto mbDestination = this->findMeasureBase();
auto boxClone = mbSource->clone();
boxClone->setPrev(this->prevMM());
boxClone->setNext(mbDestination);
score()->undo(new InsertMeasures(boxClone, boxClone));
}
break;
}
case ElementType::ICON:
switch (toIcon(e)->iconType()) {
case IconType::VFRAME:
Expand Down
137 changes: 137 additions & 0 deletions libmscore/measure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,10 @@ bool Measure::acceptDrop(EditData& data) const
case ElementType::SYMBOL:
case ElementType::CLEF:
case ElementType::STAFFTYPE_CHANGE:
case ElementType::VBOX:
case ElementType::HBOX:
case ElementType::TBOX:

viewer->setDropRectangle(staffR);
return true;

Expand Down Expand Up @@ -1697,6 +1701,19 @@ Element* Measure::drop(EditData& data)
delete e;
return cmdInsertRepeatMeasure(staffIdx);
}
case ElementType::HBOX:
case ElementType::VBOX:
case ElementType::TBOX:
{
if (auto mbSource = e->findMeasureBase()) {
auto mbDestination = this->findMeasureBase();
auto boxClone = mbSource->clone();
boxClone->setPrev(this->prevMM());
boxClone->setNext(mbDestination);
score()->undo(new InsertMeasures(boxClone, boxClone));
}
break;
}
case ElementType::ICON:
switch(toIcon(e)->iconType()) {
case IconType::VFRAME:
Expand Down Expand Up @@ -3197,6 +3214,126 @@ Measure* Measure::cloneMeasure(Score* sc, const Fraction& tick, TieMap* tieMap)
return m;
}

//---------------------------------------------------------
// cloneMeasure
//---------------------------------------------------------

Measure* Measure::cloneMeasureLimited(Score* scoreDest, const Fraction& tick, TieMap* tieMap, int startStaff, int endStaff)
{
Measure* m = new Measure(scoreDest);
m->_timesig = _timesig;
m->_len = _len;
m->_repeatCount = _repeatCount;

// Limited edition: Allow discrepancy of staves amount, to be limited by start/endStaff during cloning
// Code reuse: nearly identical to above cloneMeasure()

m->setNo(no());
m->setNoOffset(noOffset());
m->setIrregular(irregular());
m->_userStretch = _userStretch;
m->_breakMultiMeasureRest = _breakMultiMeasureRest;
m->_playbackCount = _playbackCount;

m->setTick(tick);
m->setLineBreak(lineBreak());
m->setPageBreak(pageBreak());
m->setSectionBreak(sectionBreak() ? new LayoutBreak(*sectionBreakElement()) : 0);

m->setHeader(header()); m->setTrailer(trailer());
TupletMap tupletMap;

auto fcr = scoreDest->selection().firstChordRest();
auto destStaffStart = fcr ? fcr->staffIdx() : 0;
int initTrack = (startStaff * VOICES);
int limitTrack = (endStaff * VOICES);
int destTrack = (destStaffStart * VOICES);

for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
Segment* s = new Segment(m, oseg->segmentType(), oseg->rtick());
s->setEnabled(oseg->enabled()); s->setVisible(oseg->visible());
s->setHeader(oseg->header()); s->setTrailer(oseg->trailer());

m->_segments.push_back(s);
for (int track = initTrack; track < limitTrack; ++track) {
int newTrack = track - initTrack + destTrack;
Element* oe = oseg->element(track);
for (Element* e : oseg->annotations()) {
if (e->generated() || e->track() != track)
continue;
Element* ne = e->clone();
ne->setTrack(newTrack);
ne->setOffset(e->offset());
ne->setScore(scoreDest);
s->add(ne);
}
if (!oe)
continue;
Element* ne = oe->clone();
ne->setTrack(newTrack);
if (oe->isChordRest()) {
ChordRest* ocr = toChordRest(oe);
ChordRest* ncr = toChordRest(ne);
Tuplet* ot = ocr->tuplet();
ncr->setTrack(newTrack);
if (ot) {
Tuplet* nt = tupletMap.findNew(ot);
if (nt == 0) {
nt = new Tuplet(*ot);
nt->clear();
nt->setTrack(newTrack);
nt->setScore(scoreDest);
nt->setParent(m);
nt->setTick(m->tick() + ot->rtick());
tupletMap.add(ot, nt);
}
ncr->setTuplet(nt);
nt->add(ncr);
}
if (oe->isChord()) {
Chord* och = toChord(ocr);
Chord* nch = toChord(ncr);
nch->setTrack(newTrack);
size_t n = och->notes().size();
for (size_t i = 0; i < n; ++i) {
Note* on = och->notes().at(i);
Note* nn = nch->notes().at(i);
if (on->tieFor()) {
Tie* tie = on->tieFor()->clone();
tie->setScore(scoreDest);
tie->setTrack(newTrack);
nn->setTieFor(tie);
tie->setStartNote(nn);
tieMap->add(on->tieFor(), tie);
}
if (on->tieBack()) {
Tie* tie = tieMap->findNew(on->tieBack());
if (tie) {
tie->setTrack(nch->track());
nn->setTieBack(tie);
tie->setEndNote(nn);
}
else {
qDebug("cloneMeasure: cannot find tie, track %d", newTrack);
}
}
}
}
}
ne->setOffset(oe->offset());
ne->setScore(scoreDest);
s->add(ne);
}
}
for (Element* e : el()) {
Element* ne = e->clone();
ne->setScore(scoreDest);
ne->setOffset(e->offset());
m->add(ne);
}
return m;
}

//---------------------------------------------------------
// snap
//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions libmscore/measure.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class Measure final : public MeasureBase {
ElementType type() const override { return ElementType::MEASURE; }
void setScore(Score* s) override;
Measure* cloneMeasure(Score*, const Fraction& tick, TieMap*);
Measure* cloneMeasureLimited(Score*, const Fraction& tick, TieMap*, int startStaff, int endStaff);

void read(XmlReader&, int idx);
void read(XmlReader& d) override { read(d, 0); }
Expand Down
4 changes: 3 additions & 1 deletion libmscore/measurebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ void MeasureBase::add(Element* e)
if (next())
next()->triggerLayout();
}
triggerLayout();
// Observation: Cloning a MeasureBase has an issue with triggerlayout here,
// Will keep comment in case there's a problem later to refer back here
// triggerLayout()
_el.push_back(e);
}

Expand Down
Loading

0 comments on commit 0c8d8a0

Please sign in to comment.