From c46174484645b0912e905adadae12e87794475da Mon Sep 17 00:00:00 2001 From: allejok96 Date: Wed, 23 Dec 2020 18:07:32 +0100 Subject: [PATCH 01/11] Add new note length modification tools --- data/themes/default/cut_overlaps.png | Bin 0 -> 7273 bytes data/themes/default/fill.png | Bin 0 -> 405 bytes data/themes/default/max_length.png | Bin 0 -> 192 bytes data/themes/default/min_length.png | Bin 0 -> 193 bytes include/PianoRoll.h | 2 + src/gui/editors/PianoRoll.cpp | 103 ++++++++++++++++++++++++++- 6 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 data/themes/default/cut_overlaps.png create mode 100644 data/themes/default/fill.png create mode 100644 data/themes/default/max_length.png create mode 100644 data/themes/default/min_length.png diff --git a/data/themes/default/cut_overlaps.png b/data/themes/default/cut_overlaps.png new file mode 100644 index 0000000000000000000000000000000000000000..64b044ea9df512eacc889e4375a27e8d826d61d2 GIT binary patch literal 7273 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 L$*Rn9+n#>`La}gU literal 0 HcmV?d00001 diff --git a/data/themes/default/fill.png b/data/themes/default/fill.png new file mode 100644 index 0000000000000000000000000000000000000000..1456673508f9ce0f447996174a6ce98b7ca7d9d8 GIT binary patch literal 405 zcmV;G0c!qpF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10U}96 zK~y-6#nL}3MPVEV@ZY&t1~Rje#lYwd*oDbtP-Ky!ltEa%3HduoicAuN!Jjf%yXa2;w`@K!lgFOZ@(PRS!d?38605i=m>w#a&0?>(MLAu!r`K#W6)aS- zdrak~Z7aC`PgyBN#6?6rWU(Yk-XdZoB2EjwXsxsd`p{q0q7_FCOtqGMsioF&DR@{1 zT5e+c2$ZpxLn@eW3d(`o8EEcTP!8P0bW#5WU>Na)g*G}800000NkvXXu0mjfhODbs literal 0 HcmV?d00001 diff --git a/data/themes/default/max_length.png b/data/themes/default/max_length.png new file mode 100644 index 0000000000000000000000000000000000000000..387bb793488c6a37f3538b1f456bff4ba71bd432 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3y=napU%7MffQ$fM`SSr z1K(i~W;~w1A_XYOUgGKN%Kn5$TtI_+{3XDS;S&XBN$zW}fd(^py85}Sb4q9e0O;2`_5c6? literal 0 HcmV?d00001 diff --git a/data/themes/default/min_length.png b/data/themes/default/min_length.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc67bdb0b08901581e79756f4e2fc6c60187f8d GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3y=napU%7MffQ$fM`SSr z1K(i~W;~w1A_XYOUgGKN%Kn5$TtI_|@sq(Lppc)Zi(`nz>Er~7Hw_>E0|BR2Qc8-- zEeAFrsA-#&ByqaddJournalCheckPoint(); + + NoteVector notes = getSelectedNotes(); + if (notes.empty()) + { + notes = m_pattern->notes(); + } + + // Sort notes by position + std::sort(notes.begin(), notes.end(), [](const Note *n1, const Note *n2){ return n1->pos() < n2->pos(); }); + + NoteVector chordGroup; + TimePos chordLength; + for (int i = 0; i < notes.count(); i++) + { + chordGroup.append(notes[i]); + + // Stretch last chord to end of bar + if (i+1 == notes.count()) + { + chordLength = notes[i]->endPos().nextFullBar() * TimePos::ticksPerBar() - notes[i]->pos(); + } + // Stretch chord to next note + else if (notes[i]->pos() != notes[i+1]->pos()) + { + chordLength = notes[i+1]->pos() - notes[i]->pos(); + } + // There are more notes in the chord + else + { + continue; + } + + for (Note *chordNote: chordGroup) + { + if ((shrink && chordNote->length() > chordLength) + || (grow && chordNote->length() < chordLength)) + { + chordNote->setLength(chordLength); + } + } + chordGroup.clear(); + } + + update(); + gui->songEditor()->update(); + Engine::getSong()->setModified(); + } +} + + +void PianoRoll::limitNoteLengths(bool minimumLimit) +{ + if (hasValidPattern()) + { + m_pattern->addJournalCheckPoint(); + + NoteVector notes = getSelectedNotes(); + if (notes.empty()) + { + notes = m_pattern->notes(); + } + + TimePos limit = m_lenOfNewNotes; // length of last note + for (Note *note : notes) + { + if ((minimumLimit && note->length() < limit) + || (!minimumLimit && note->length() > limit)) + { + note->setLength(limit); + } + } + + update(); + gui->songEditor()->update(); + Engine::getSong()->setModified(); + } +} + void PianoRoll::loadMarkedSemiTones(const QDomElement & de) { @@ -4432,18 +4515,34 @@ PianoRollWindow::PianoRollWindow() : m_editor->m_timeLine->addToolButtons( timeLineToolBar ); // -- Note modifier tools - // Toolbar QToolButton * noteToolsButton = new QToolButton(m_toolBar); noteToolsButton->setIcon(embed::getIconPixmap("tool")); noteToolsButton->setPopupMode(QToolButton::InstantPopup); - // Glue QAction * glueAction = new QAction(embed::getIconPixmap("glue"), tr("Glue"), noteToolsButton); connect(glueAction, SIGNAL(triggered()), m_editor, SLOT(glueNotes())); glueAction->setShortcut( Qt::SHIFT | Qt::Key_G ); + QAction *fillAction = new QAction(embed::getIconPixmap("fill"), tr("Fill"), noteToolsButton); + connect(fillAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(false, true); }); + fillAction->setShortcut( Qt::SHIFT | Qt::Key_F ); + + QAction *cutOverlapsAction = new QAction(embed::getIconPixmap("cut_overlaps"), tr("Cut overlaps"), noteToolsButton); + connect(cutOverlapsAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(true, false); }); + cutOverlapsAction->setShortcut( Qt::SHIFT | Qt::Key_C ); + + QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as latest"), noteToolsButton); + connect(minLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(true); }); + + QAction *maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as latest"), noteToolsButton); + connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(false); }); + noteToolsButton->addAction(glueAction); + noteToolsButton->addAction(fillAction); + noteToolsButton->addAction(cutOverlapsAction); + noteToolsButton->addAction(minLengthAction); + noteToolsButton->addAction(maxLengthAction); notesActionsToolBar->addWidget(noteToolsButton); From 59d65c147c5c7a44a7219aa16ff61e181dccfddc Mon Sep 17 00:00:00 2001 From: allejok96 Date: Tue, 29 Dec 2020 10:56:04 +0100 Subject: [PATCH 02/11] "Last" instead of "latest" --- src/gui/editors/PianoRoll.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 3edda629f5b..00cad376f8d 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -4532,10 +4532,10 @@ PianoRollWindow::PianoRollWindow() : connect(cutOverlapsAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(true, false); }); cutOverlapsAction->setShortcut( Qt::SHIFT | Qt::Key_C ); - QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as latest"), noteToolsButton); + QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as last"), noteToolsButton); connect(minLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(true); }); - QAction *maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as latest"), noteToolsButton); + QAction *maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as last"), noteToolsButton); connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(false); }); noteToolsButton->addAction(glueAction); From 99796a65da0e56bfe17d74ecc7f8c8eb4ab4ab6c Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 30 Dec 2020 22:00:06 +0100 Subject: [PATCH 03/11] Code formatting Co-authored-by: IanCaio --- src/gui/editors/PianoRoll.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 00cad376f8d..c772e9e2077 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -725,7 +725,11 @@ void PianoRoll::fitNoteLengths(bool shrink, bool grow) } // Sort notes by position - std::sort(notes.begin(), notes.end(), [](const Note *n1, const Note *n2){ return n1->pos() < n2->pos(); }); + std::sort( + notes.begin(), + notes.end(), + [](const Note *n1, const Note *n2){ return n1->pos() < n2->pos(); } + ); NoteVector chordGroup; TimePos chordLength; From 61a14337e32419ee43dea25971386e527b62b46c Mon Sep 17 00:00:00 2001 From: allejok96 Date: Fri, 8 Jan 2021 17:39:16 +0100 Subject: [PATCH 04/11] Fix sort --- src/gui/editors/PianoRoll.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index c772e9e2077..7b674b74957 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -725,11 +725,7 @@ void PianoRoll::fitNoteLengths(bool shrink, bool grow) } // Sort notes by position - std::sort( - notes.begin(), - notes.end(), - [](const Note *n1, const Note *n2){ return n1->pos() < n2->pos(); } - ); + std::sort(notes.begin(), notes.end(), Note::lessThan); NoteVector chordGroup; TimePos chordLength; From 0cf824ff26ecf2221d4ee469b2147e1e88efa8a9 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Sat, 16 Jan 2021 20:15:40 +0100 Subject: [PATCH 05/11] Fix incorrect cut of last note --- src/gui/editors/PianoRoll.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 7b674b74957..46fc9296cac 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -724,8 +724,13 @@ void PianoRoll::fitNoteLengths(bool shrink, bool grow) notes = m_pattern->notes(); } - // Sort notes by position - std::sort(notes.begin(), notes.end(), Note::lessThan); + // Sort notes by position, then length + std::sort(notes.begin(), notes.end(), [](const Note *n1, const Note *n2) { + if (n1->pos() == n2->pos()) { + return n1->length() < n2->length(); + } + return n1->pos() < n2->pos(); + }); NoteVector chordGroup; TimePos chordLength; @@ -734,6 +739,7 @@ void PianoRoll::fitNoteLengths(bool shrink, bool grow) chordGroup.append(notes[i]); // Stretch last chord to end of bar + // in this case notes[i] will always be the longest note in the chord if (i+1 == notes.count()) { chordLength = notes[i]->endPos().nextFullBar() * TimePos::ticksPerBar() - notes[i]->pos(); From 1839737a2a1515af8dd8245a05bf9f2bdeeaf8c3 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Sat, 30 Jan 2021 22:11:48 +0100 Subject: [PATCH 06/11] Fix Fill not stretching last note to end --- src/gui/editors/PianoRoll.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 46fc9296cac..1b6eef882a0 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -724,25 +724,23 @@ void PianoRoll::fitNoteLengths(bool shrink, bool grow) notes = m_pattern->notes(); } - // Sort notes by position, then length - std::sort(notes.begin(), notes.end(), [](const Note *n1, const Note *n2) { - if (n1->pos() == n2->pos()) { - return n1->length() < n2->length(); - } - return n1->pos() < n2->pos(); - }); + // Sort notes by position + std::sort(notes.begin(), notes.end(), Note::lessThan); NoteVector chordGroup; TimePos chordLength; + TimePos lastEndPos(0); + for (int i = 0; i < notes.count(); i++) { + lastEndPos = qMax(notes[i]->endPos(), lastEndPos); + chordGroup.append(notes[i]); - // Stretch last chord to end of bar - // in this case notes[i] will always be the longest note in the chord + // Stretch last chord to end of last bar if (i+1 == notes.count()) { - chordLength = notes[i]->endPos().nextFullBar() * TimePos::ticksPerBar() - notes[i]->pos(); + chordLength = lastEndPos.nextFullBar() * TimePos::ticksPerBar() - notes[i]->pos(); } // Stretch chord to next note else if (notes[i]->pos() != notes[i+1]->pos()) From e1f5ee92291761e9aeef54a0d800de6f1b127235 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Wed, 3 Feb 2021 19:38:23 +0100 Subject: [PATCH 07/11] Fill from end positions --- include/PianoRoll.h | 2 +- src/gui/editors/PianoRoll.cpp | 91 ++++++++++++++++------------------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 5b03ab45d98..c70181a3f17 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -209,7 +209,7 @@ protected slots: void clearGhostPattern(); void glueNotes(); - void fitNoteLengths(bool shrink, bool grow); + void fitNoteLengths(bool fill); void limitNoteLengths(bool minimumLimit); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 1b6eef882a0..029100c8eec 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -712,62 +712,53 @@ void PianoRoll::glueNotes() } } -void PianoRoll::fitNoteLengths(bool shrink, bool grow) +void PianoRoll::fitNoteLengths(bool fill) { - if (hasValidPattern()) + if (!hasValidPattern()) { return; } + m_pattern->addJournalCheckPoint(); + + NoteVector refNotes = getSelectedNotes(); + if (refNotes.empty()) { - m_pattern->addJournalCheckPoint(); + refNotes = m_pattern->notes(); + } + // Sort by start position + std::sort(refNotes.begin(), refNotes.end(), Note::lessThan); - NoteVector notes = getSelectedNotes(); - if (notes.empty()) + NoteVector notes = refNotes; + if (fill) + { + // Sort by end position when filling + std::sort(notes.begin(), notes.end(), [](Note *n1, Note *n2) { return n1->endPos() < n2->endPos(); }); + } + + int length; + NoteVector::iterator ref = refNotes.begin(); + for (Note *note : notes) + { + // Fast forward to next reference note + while (ref != refNotes.end() && (fill ? (*ref)->pos() < note->endPos() : (*ref)->pos() <= note->pos())) { - notes = m_pattern->notes(); + ref++; } - - // Sort notes by position - std::sort(notes.begin(), notes.end(), Note::lessThan); - - NoteVector chordGroup; - TimePos chordLength; - TimePos lastEndPos(0); - - for (int i = 0; i < notes.count(); i++) + if (ref == refNotes.end()) { - lastEndPos = qMax(notes[i]->endPos(), lastEndPos); - - chordGroup.append(notes[i]); - - // Stretch last chord to end of last bar - if (i+1 == notes.count()) - { - chordLength = lastEndPos.nextFullBar() * TimePos::ticksPerBar() - notes[i]->pos(); - } - // Stretch chord to next note - else if (notes[i]->pos() != notes[i+1]->pos()) - { - chordLength = notes[i+1]->pos() - notes[i]->pos(); - } - // There are more notes in the chord - else - { - continue; - } - - for (Note *chordNote: chordGroup) - { - if ((shrink && chordNote->length() > chordLength) - || (grow && chordNote->length() < chordLength)) - { - chordNote->setLength(chordLength); - } - } - chordGroup.clear(); + // Last notes stretch to end of last bar + length = notes.last()->endPos().nextFullBar() * TimePos::ticksPerBar() - note->pos(); + } + else + { + length = (*ref)->pos() - note->pos(); + } + if (fill ? note->length() < length : note->length() > length) + { + note->setLength(length); } - - update(); - gui->songEditor()->update(); - Engine::getSong()->setModified(); } + + update(); + gui->songEditor()->update(); + Engine::getSong()->setModified(); } @@ -4529,11 +4520,11 @@ PianoRollWindow::PianoRollWindow() : glueAction->setShortcut( Qt::SHIFT | Qt::Key_G ); QAction *fillAction = new QAction(embed::getIconPixmap("fill"), tr("Fill"), noteToolsButton); - connect(fillAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(false, true); }); + connect(fillAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(true); }); fillAction->setShortcut( Qt::SHIFT | Qt::Key_F ); QAction *cutOverlapsAction = new QAction(embed::getIconPixmap("cut_overlaps"), tr("Cut overlaps"), noteToolsButton); - connect(cutOverlapsAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(true, false); }); + connect(cutOverlapsAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(false); }); cutOverlapsAction->setShortcut( Qt::SHIFT | Qt::Key_C ); QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as last"), noteToolsButton); From 10d6de1baeda086d1e6fa4962ba081e9a2dc871f Mon Sep 17 00:00:00 2001 From: allejok96 Date: Wed, 3 Feb 2021 20:05:06 +0100 Subject: [PATCH 08/11] Rename limitNoteLengths --- include/PianoRoll.h | 2 +- src/gui/editors/PianoRoll.cpp | 41 ++++++++++++++++------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index c70181a3f17..2f4b7834092 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -210,7 +210,7 @@ protected slots: void clearGhostPattern(); void glueNotes(); void fitNoteLengths(bool fill); - void limitNoteLengths(bool minimumLimit); + void constrainNoteLengths(bool constrainMax); signals: diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 029100c8eec..7af5da6fb81 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -762,32 +762,29 @@ void PianoRoll::fitNoteLengths(bool fill) } -void PianoRoll::limitNoteLengths(bool minimumLimit) +void PianoRoll::constrainNoteLengths(bool constrainMax) { - if (hasValidPattern()) + if (!hasValidPattern()) { return; } + m_pattern->addJournalCheckPoint(); + + NoteVector notes = getSelectedNotes(); + if (notes.empty()) { - m_pattern->addJournalCheckPoint(); + notes = m_pattern->notes(); + } - NoteVector notes = getSelectedNotes(); - if (notes.empty()) + TimePos bound = m_lenOfNewNotes; // will be length of last note + for (Note *note : notes) + { + if (constrainMax ? note->length() > bound : note->length() < bound) { - notes = m_pattern->notes(); - } - - TimePos limit = m_lenOfNewNotes; // length of last note - for (Note *note : notes) - { - if ((minimumLimit && note->length() < limit) - || (!minimumLimit && note->length() > limit)) - { - note->setLength(limit); - } + note->setLength(bound); } - - update(); - gui->songEditor()->update(); - Engine::getSong()->setModified(); } + + update(); + gui->songEditor()->update(); + Engine::getSong()->setModified(); } @@ -4528,10 +4525,10 @@ PianoRollWindow::PianoRollWindow() : cutOverlapsAction->setShortcut( Qt::SHIFT | Qt::Key_C ); QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as last"), noteToolsButton); - connect(minLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(true); }); + connect(minLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(false); }); QAction *maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as last"), noteToolsButton); - connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->limitNoteLengths(false); }); + connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(true); }); noteToolsButton->addAction(glueAction); noteToolsButton->addAction(fillAction); From 2832471bfba94db68aef00a900c8f8cf5a4ea9e0 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Wed, 3 Feb 2021 20:06:06 +0100 Subject: [PATCH 09/11] Compare with non-selected notes when filling --- src/gui/editors/PianoRoll.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 7af5da6fb81..ecf4cd0aa33 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -717,18 +717,22 @@ void PianoRoll::fitNoteLengths(bool fill) if (!hasValidPattern()) { return; } m_pattern->addJournalCheckPoint(); - NoteVector refNotes = getSelectedNotes(); - if (refNotes.empty()) - { - refNotes = m_pattern->notes(); - } - // Sort by start position + // Reference notes + NoteVector refNotes = m_pattern->notes(); std::sort(refNotes.begin(), refNotes.end(), Note::lessThan); - NoteVector notes = refNotes; + // Notes to edit + NoteVector notes = getSelectedNotes(); + if (notes.empty()) + { + notes = refNotes; + } + else if (!fill) + { + std::sort(notes.begin(), notes.end(), Note::lessThan); + } if (fill) { - // Sort by end position when filling std::sort(notes.begin(), notes.end(), [](Note *n1, Note *n2) { return n1->endPos() < n2->endPos(); }); } From f19331fc73918cdf7abc39ec85991056077c6250 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Fri, 5 Feb 2021 20:41:29 +0100 Subject: [PATCH 10/11] Style changes by IanCaio + bugfix --- src/gui/editors/PianoRoll.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index ecf4cd0aa33..4d5be14b796 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -733,12 +733,12 @@ void PianoRoll::fitNoteLengths(bool fill) } if (fill) { - std::sort(notes.begin(), notes.end(), [](Note *n1, Note *n2) { return n1->endPos() < n2->endPos(); }); + std::sort(notes.begin(), notes.end(), [](Note* n1, Note* n2) { return n1->endPos() < n2->endPos(); }); } int length; NoteVector::iterator ref = refNotes.begin(); - for (Note *note : notes) + for (Note* note : notes) { // Fast forward to next reference note while (ref != refNotes.end() && (fill ? (*ref)->pos() < note->endPos() : (*ref)->pos() <= note->pos())) @@ -747,6 +747,7 @@ void PianoRoll::fitNoteLengths(bool fill) } if (ref == refNotes.end()) { + if (!fill) { continue; } // Last notes stretch to end of last bar length = notes.last()->endPos().nextFullBar() * TimePos::ticksPerBar() - note->pos(); } @@ -778,7 +779,7 @@ void PianoRoll::constrainNoteLengths(bool constrainMax) } TimePos bound = m_lenOfNewNotes; // will be length of last note - for (Note *note : notes) + for (Note* note : notes) { if (constrainMax ? note->length() > bound : note->length() < bound) { @@ -4520,18 +4521,18 @@ PianoRollWindow::PianoRollWindow() : connect(glueAction, SIGNAL(triggered()), m_editor, SLOT(glueNotes())); glueAction->setShortcut( Qt::SHIFT | Qt::Key_G ); - QAction *fillAction = new QAction(embed::getIconPixmap("fill"), tr("Fill"), noteToolsButton); + QAction* fillAction = new QAction(embed::getIconPixmap("fill"), tr("Fill"), noteToolsButton); connect(fillAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(true); }); - fillAction->setShortcut( Qt::SHIFT | Qt::Key_F ); + fillAction->setShortcut(Qt::SHIFT | Qt::Key_F); - QAction *cutOverlapsAction = new QAction(embed::getIconPixmap("cut_overlaps"), tr("Cut overlaps"), noteToolsButton); + QAction* cutOverlapsAction = new QAction(embed::getIconPixmap("cut_overlaps"), tr("Cut overlaps"), noteToolsButton); connect(cutOverlapsAction, &QAction::triggered, [this](){ m_editor->fitNoteLengths(false); }); - cutOverlapsAction->setShortcut( Qt::SHIFT | Qt::Key_C ); + cutOverlapsAction->setShortcut(Qt::SHIFT | Qt::Key_C); - QAction *minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as last"), noteToolsButton); + QAction* minLengthAction = new QAction(embed::getIconPixmap("min_length"), tr("Min length as last"), noteToolsButton); connect(minLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(false); }); - QAction *maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as last"), noteToolsButton); + QAction* maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as last"), noteToolsButton); connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(true); }); noteToolsButton->addAction(glueAction); From 1065f84449da3bb974da22de5cc3b759d8239c07 Mon Sep 17 00:00:00 2001 From: allejok96 Date: Sun, 7 Feb 2021 16:22:41 +0100 Subject: [PATCH 11/11] break instead of continue --- src/gui/editors/PianoRoll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 4d5be14b796..91ae1c2c88a 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -747,7 +747,7 @@ void PianoRoll::fitNoteLengths(bool fill) } if (ref == refNotes.end()) { - if (!fill) { continue; } + if (!fill) { break; } // Last notes stretch to end of last bar length = notes.last()->endPos().nextFullBar() * TimePos::ticksPerBar() - note->pos(); }