diff --git a/src/engraving/editing/edit.cpp b/src/engraving/editing/edit.cpp index 0814e7b306922..aea25fb62639f 100644 --- a/src/engraving/editing/edit.cpp +++ b/src/engraving/editing/edit.cpp @@ -2042,7 +2042,10 @@ static Tie* createAndAddTie(Note* startNote, Note* endNote) void Score::cmdAddTie(bool addToChord) { - const std::vector noteList = cmdTieNoteList(selection(), noteEntryMode()); + std::vector noteList = cmdTieNoteList(selection(), noteEntryMode()); + std::vector 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"); @@ -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(); } @@ -2165,25 +2167,36 @@ Tie* Score::cmdToggleTie() return nullptr; } - bool canAddTies = false; - const size_t notes = noteList.size(); - std::vector tieNoteList(notes); - const bool shouldTieListSelection = notes >= 2; - - for (size_t i = 0; i < notes; ++i) { + std::vector 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"); @@ -2191,7 +2204,7 @@ Tie* Score::cmdToggleTie() 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]; @@ -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); @@ -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;