4 new note modification tools (#5857)

* Add new note length modification tools

* "Last" instead of "latest"

* Code formatting

Co-authored-by: IanCaio <iancaio_dev@hotmail.com>

* Fix sort

* Fix incorrect cut of last note

* Fix Fill not stretching last note to end

* Fill from end positions

* Rename limitNoteLengths

* Compare with non-selected notes when filling

* Style changes by IanCaio + bugfix

* break instead of continue

Co-authored-by: IanCaio <iancaio_dev@hotmail.com>
This commit is contained in:
Alex
2021-03-05 13:31:27 +01:00
committed by GitHub
parent e880e3cb2a
commit 5d366ef06f
6 changed files with 100 additions and 3 deletions

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

View File

@@ -211,6 +211,8 @@ protected slots:
void clearGhostPattern();
void glueNotes();
void fitNoteLengths(bool fill);
void constrainNoteLengths(bool constrainMax);
signals:

View File

@@ -718,6 +718,86 @@ void PianoRoll::glueNotes()
}
}
void PianoRoll::fitNoteLengths(bool fill)
{
if (!hasValidPattern()) { return; }
m_pattern->addJournalCheckPoint();
// Reference notes
NoteVector refNotes = m_pattern->notes();
std::sort(refNotes.begin(), refNotes.end(), Note::lessThan);
// Notes to edit
NoteVector notes = getSelectedNotes();
if (notes.empty())
{
notes = refNotes;
}
else if (!fill)
{
std::sort(notes.begin(), notes.end(), Note::lessThan);
}
if (fill)
{
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()))
{
ref++;
}
if (ref == refNotes.end())
{
if (!fill) { break; }
// 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();
}
void PianoRoll::constrainNoteLengths(bool constrainMax)
{
if (!hasValidPattern()) { return; }
m_pattern->addJournalCheckPoint();
NoteVector notes = getSelectedNotes();
if (notes.empty())
{
notes = m_pattern->notes();
}
TimePos bound = m_lenOfNewNotes; // will be length of last note
for (Note* note : notes)
{
if (constrainMax ? note->length() > bound : note->length() < bound)
{
note->setLength(bound);
}
}
update();
gui->songEditor()->update();
Engine::getSong()->setModified();
}
void PianoRoll::loadMarkedSemiTones(const QDomElement & de)
{
@@ -4603,25 +4683,40 @@ 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 );
// Knife
QAction * knifeAction = new QAction(embed::getIconPixmap("edit_knife"),
tr("Knife"), noteToolsButton);
connect(knifeAction, &QAction::triggered, m_editor, &PianoRoll::setKnifeAction);
knifeAction->setShortcut( Qt::SHIFT | Qt::Key_K );
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);
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);
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);
connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(true); });
noteToolsButton->addAction(glueAction);
noteToolsButton->addAction(knifeAction);
noteToolsButton->addAction(fillAction);
noteToolsButton->addAction(cutOverlapsAction);
noteToolsButton->addAction(minLengthAction);
noteToolsButton->addAction(maxLengthAction);
notesActionsToolBar->addWidget(noteToolsButton);