Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 97 additions & 84 deletions src/engraving/editing/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,10 @@ static Tie* createAndAddTie(Note* startNote, Note* endNote)

void Score::cmdAddTie(bool addToChord)
{
const std::vector<Note*> noteList = cmdTieNoteList(selection(), noteEntryMode());
std::vector<Note*> noteList = cmdTieNoteList(selection(), noteEntryMode());
std::vector<EngravingItem*> toSelect;
std::sort(noteList.begin(), noteList.end(), [](const Note* a, const Note* b) { return a->track() < b->track(); });
track_idx_t track = noteList[0]->chord()->track();

if (noteList.empty()) {
LOGD("no notes selected");
Expand All @@ -2062,93 +2065,92 @@ void Score::cmdAddTie(bool addToChord)
}
}

if (noteEntryMode()) {
ChordRest* cr = nullptr;
Chord* c = note->chord();
int staffMove = c->staffMove();

// set cursor at position after note
if (c->isGraceBefore()) {
// tie grace note before to main note
cr = toChord(c->explicitParent());
addToChord = true;
} else {
m_is.setSegment(note->chord()->segment());
m_is.moveToNextInputPos();
m_is.setLastSegment(m_is.segment());
ChordRest* cr = nullptr;
Chord* c = note->chord();
int staffMove = c->staffMove();

// set cursor at position after note
if (c->isGraceBefore()) {
// tie grace note before to main note
cr = toChord(c->explicitParent());
addToChord = true;
} else {
m_is.setTrack(note->chord()->track());
m_is.setSegment(note->chord()->segment());
m_is.moveToNextInputPos();
m_is.setLastSegment(m_is.segment());

if (!m_is.cr()) {
expandVoice();
}
cr = m_is.cr();
}
if (!cr) {
break;
if (!m_is.cr()) {
expandVoice();
}
cr = m_is.cr();
}
if (!cr) {
break;
}

bool addFlag = lastAddedChord != nullptr;

// try to re-use existing note or chord
Note* n = nullptr;
if (addToChord && cr->isChord()) {
Chord* chord = toChord(cr);
Note* nn = chord->findNote(note->pitch());
if (nn && nn->tpc() == note->tpc()) {
n = nn; // re-use note
} else {
addFlag = true; // re-use chord
}
bool addFlag = lastAddedChord != nullptr;
if (c->track() != track) {
addFlag = false;
track = c->track();
}
// try to re-use existing note or chord
Note* n = nullptr;
if (addToChord && cr->isChord()) {
Chord* chord = toChord(cr);
Note* nn = chord->findNote(note->pitch());
if (nn && nn->tpc() == note->tpc()) {
n = nn; // re-use note
} else {
addFlag = true; // re-use chord
}
}

// if no note to re-use, create one
NoteVal nval(note->noteVal());
if (!n) {
n = addPitch(nval, addFlag);
if (staffMove != 0) {
undo(new ChangeChordStaffMove(n->chord(), staffMove));
}
} else {
select(n);
// if no note to re-use, create one
NoteVal nval(note->noteVal());
if (!n) {
n = addPitch(nval, addFlag);
if (staffMove != 0) {
undo(new ChangeChordStaffMove(n->chord(), staffMove));
}
} else {
select(n);
}

if (n) {
if (!lastAddedChord) {
lastAddedChord = n->chord();
}
// n is not necessarily next note if duration span over measure
Note* nnote = searchTieNote(note);
while (nnote) {
// DEBUG: if duration spans over measure
// this does not set line for intermediate notes
// tpc was set correctly already
//n->setLine(note->line());
//n->setTpc(note->tpc());
createAndAddTie(note, nnote);
if (n) {
if (!lastAddedChord) {
lastAddedChord = n->chord();
}
// n is not necessarily next note if duration span over measure
Note* nnote = searchTieNote(note);
while (nnote) {
// DEBUG: if duration spans over measure
// this does not set line for intermediate notes
// tpc was set correctly already
//n->setLine(note->line());
//n->setTpc(note->tpc());
createAndAddTie(note, nnote);

if (!addFlag || nnote->chord()->tick() >= lastAddedChord->tick() || nnote->chord()->isGrace()) {
break;
} else {
note = nnote;
m_is.setLastSegment(m_is.segment());
nnote = addPitch(nval, true);
}
}
if (staffMove != 0) {
for (Note* tiedNote : n->tiedNotes()) {
undo(new ChangeChordStaffMove(tiedNote->chord(), staffMove));
}
if (!addFlag || nnote->chord()->tick() >= lastAddedChord->tick() || nnote->chord()->isGrace()) {
break;
} else {
note = nnote;
m_is.setLastSegment(m_is.segment());
nnote = addPitch(nval, true);
}
}
} else {
Note* note2 = searchTieNote(note);
if (note2) {
createAndAddTie(note, note2);
if (staffMove != 0) {
for (Note* tiedNote : n->tiedNotes()) {
undo(new ChangeChordStaffMove(tiedNote->chord(), staffMove));
}
}
}
toSelect.push_back(n);
}
if (lastAddedChord) {
nextInputPos(lastAddedChord, false);
}
score()->select(toSelect, SelectType::ADD);
endCmd();
}

Expand All @@ -2165,33 +2167,44 @@ Tie* Score::cmdToggleTie()
return nullptr;
}

bool canAddTies = false;
const size_t notes = noteList.size();
std::vector<Note*> tieNoteList(notes);
const bool shouldTieListSelection = notes >= 2;

for (size_t i = 0; i < notes; ++i) {
std::vector<Note*> tieNoteList(noteList.size());
bool singleTick = true;
bool someHaveExistingNextNoteToTieTo = false;
bool allHaveExistingNextNoteToTieTo = true;
for (size_t i = 0; i < noteList.size(); ++i) {
Note* n = noteList[i];
if (n->chord()->tick() != noteList.front()->tick()) {
singleTick = false;
}
if (n->tieFor()) {
tieNoteList[i] = nullptr;
} else {
Note* tieNote = searchTieNote(n);
tieNoteList[i] = tieNote;
if (tieNote) {
canAddTies = true;
someHaveExistingNextNoteToTieTo = true;
} else {
allHaveExistingNextNoteToTieTo = false;
}
}
}

const TranslatableString actionName = canAddTies
const bool shouldTieListSelection = noteList.size() >= 2 && !singleTick;

if (singleTick /* i.e. all notes are in the same tick */ && !allHaveExistingNextNoteToTieTo) {
cmdAddTie();
return nullptr;
}

const TranslatableString actionName = someHaveExistingNextNoteToTieTo
? TranslatableString("undoableAction", "Add tie")
: TranslatableString("undoableAction", "Remove tie");

startCmd(actionName);

Tie* tie = nullptr;

for (size_t i = 0; i < notes; ++i) {
for (size_t i = 0; i < noteList.size(); ++i) {
Note* note = noteList[i];
Note* tieToNote = tieNoteList[i];

Expand All @@ -2200,7 +2213,7 @@ Tie* Score::cmdToggleTie()
}

// Tie to adjacent unselected note
if (canAddTies && tieToNote) {
if (someHaveExistingNextNoteToTieTo && tieToNote) {
Note* startNote = note->tick() <= tieToNote->tick() ? note : tieToNote;
Note* endNote = startNote == tieToNote ? note : tieToNote;
tie = createAndAddTie(startNote, endNote);
Expand All @@ -2224,14 +2237,14 @@ Tie* Score::cmdToggleTie()
continue;
}

if (!shouldTieListSelection || i > notes - 2) {
if (!shouldTieListSelection || i > noteList.size() - 2) {
continue;
}

// Tie to next appropriate note in selection
Note* note2 = nullptr;

for (size_t j = i + 1; j < notes; ++j) {
for (size_t j = i + 1; j < noteList.size(); ++j) {
Note* candidateNote = noteList[j];
if (!candidateNote) {
continue;
Expand Down
Loading