Skip to content
Open
Show file tree
Hide file tree
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
Binary file added data/themes/default/square_square.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions include/MidiClip.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class LMMS_EXPORT MidiClip : public Clip
//! Horizontally flip the positions of the given notes.
void reverseNotes(const NoteVector& notes);

//! Vertically flip the positions of the given notes.
void flipNotes(const NoteVector& notes);

// Split the list of notes on the given position
void splitNotes(const NoteVector& notes, TimePos pos);

Expand Down
4 changes: 3 additions & 1 deletion include/PianoRoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ protected slots:
void copySelectedNotes();
void cutSelectedNotes();
void pasteNotes();
void duplicateNotes();
bool deleteSelectedNotes();

void updatePosition(const lmms::TimePos & t );
Expand All @@ -246,6 +247,7 @@ protected slots:
void glueNotes();
void fitNoteLengths(bool fill);
void reverseNotes();
void flipNotes();
void constrainNoteLengths(bool constrainMax);

void changeSnapMode();
Expand Down Expand Up @@ -359,7 +361,7 @@ protected slots:

static SimpleTextFloat * s_textFloat;

ComboBoxModel m_zoomingModel;
ComboBoxModel m_zoomingXModel;
ComboBoxModel m_zoomingYModel;
ComboBoxModel m_quantizeModel;
ComboBoxModel m_noteLenModel;
Expand Down
38 changes: 38 additions & 0 deletions src/gui/editors/AutomationEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,51 +254,89 @@



void AutomationEditor::keyPressEvent(QKeyEvent * ke )
{
switch( ke->key() )
{
case Qt::Key_Up:
m_topBottomScroll->setValue(
m_topBottomScroll->value() - 1 );
ke->accept();
break;

case Qt::Key_Down:
m_topBottomScroll->setValue(
m_topBottomScroll->value() + 1 );
ke->accept();
break;

case Qt::Key_Left:
if( ( m_timeLine->pos() -= 16 ) < 0 )
{
m_timeLine->pos().setTicks( 0 );
}
m_timeLine->updatePosition();
ke->accept();
break;

case Qt::Key_Right:
m_timeLine->pos() += 16;
m_timeLine->updatePosition();
ke->accept();
break;

case Qt::Key_Home:
m_timeLine->pos().setTicks( 0 );
m_timeLine->updatePosition();
ke->accept();
break;

case Qt::Key_Minus:
if (ke->modifiers() & Qt::ControlModifier)
{
// ctrl - will zoom x out
int value = m_zoomingXModel.value();
m_zoomingXModel.setValue(value - 1);
}
if (ke->modifiers() & Qt::AltModifier)
{
// ctrl = will zoom y out
int value = m_zoomingYModel.value();
m_zoomingYModel.setValue(value - 1);
}
break;

case Qt::Key_Equal:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do these as a QAction too?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that, this just seemed like a more straight forward approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use QKeySequence::ZoomIn and ZoomOut. That solves the issue with different keyboard layouts and platforms. For example, on my keyboard 0=} is the same key, and ?+\ is another key

if (ke->modifiers() & Qt::ControlModifier)
{
// ctrl = will zoom x in
int value = m_zoomingXModel.value();
m_zoomingXModel.setValue(value + 1);
}
if (ke->modifiers() & Qt::AltModifier)
{
// ctrl = will zoom y in
int value = m_zoomingYModel.value();
m_zoomingYModel.setValue(value + 1);
}
break;

case Qt::Key_0:
// Ctrl+0 will reset both zooms
if (ke->modifiers() & Qt::ControlModifier)
{
m_zoomingYModel.setValue(0);
m_zoomingXModel.setValue(3);
}
break;
default:
ke->ignore();
break;
}
}



Check notice on line 339 in src/gui/editors/AutomationEditor.cpp

View check run for this annotation

codefactor.io / CodeFactor

src/gui/editors/AutomationEditor.cpp#L257-L339

Complex Method

void AutomationEditor::leaveEvent(QEvent * e )
{
Expand Down
98 changes: 82 additions & 16 deletions src/gui/editors/PianoRoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const std::vector<float> PianoRoll::m_zoomYLevels =
PianoRoll::PianoRoll() :
m_noteEditMenu( nullptr ),
m_semiToneMarkerMenu( nullptr ),
m_zoomingModel(),
m_zoomingXModel(),
m_zoomingYModel(),
m_quantizeModel(),
m_noteLenModel(),
Expand Down Expand Up @@ -316,10 +316,10 @@ PianoRoll::PianoRoll() :
// setup zooming-stuff
for( float const & zoomLevel : m_zoomLevels )
{
m_zoomingModel.addItem(QString("%1%").arg(zoomLevel * 100));
m_zoomingXModel.addItem(QString("%1%").arg(zoomLevel * 100));
}
m_zoomingModel.setValue( m_zoomingModel.findText( "100%" ) );
connect( &m_zoomingModel, SIGNAL(dataChanged()),
m_zoomingXModel.setValue( m_zoomingXModel.findText( "100%" ) );
connect( &m_zoomingXModel, SIGNAL(dataChanged()),
this, SLOT(zoomingChanged()));

// zoom y
Expand Down Expand Up @@ -778,6 +778,20 @@ void PianoRoll::constrainNoteLengths(bool constrainMax)
Engine::getSong()->setModified();
}

void PianoRoll::flipNotes()
{
if (!hasValidMidiClip()) { return; }

const NoteVector selectedNotes = getSelectedNotes();
const auto& notes = selectedNotes.empty() ? m_midiClip->notes() : selectedNotes;

m_midiClip->flipNotes(notes);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that having Clip::flipNotes is neat, but I don't like that you can pass notes from any clip to it (yeah reverseNotes does it too). I'd rather see that the selection happens inside Clip::flipNotes. It's not a deal breaker though... I need a second opinion on this...


update();
getGUI()->songEditor()->update();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these update calls needed? Try without. At least the first one should not be needed since the editor connects to Clip::dataChanged

Engine::getSong()->setModified();
}

void PianoRoll::reverseNotes()
{
if (!hasValidMidiClip()) { return; }
Expand All @@ -792,7 +806,6 @@ void PianoRoll::reverseNotes()
Engine::getSong()->setModified();
}


void PianoRoll::loadMarkedSemiTones(const QDomElement & de)
{
// clear marked semitones to prevent leftover marks
Expand Down Expand Up @@ -1414,6 +1427,36 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke)
break;
}

case Qt::Key_Minus:
if (ke->modifiers() & Qt::ControlModifier)
{
// ctrl - will zoom out
int value = m_zoomingXModel.value();
m_zoomingXModel.setValue(value - 1);
}
if (ke->modifiers() & Qt::AltModifier)
{
// alt = will zoom y out
int value = m_zoomingYModel.value();
m_zoomingYModel.setValue(value - 1);
}
break;

case Qt::Key_Equal:
if (ke->modifiers() & Qt::ControlModifier)
{
// ctrl = will zoom x in
int value = m_zoomingXModel.value();
m_zoomingXModel.setValue(value + 1);
}
if (ke->modifiers() & Qt::AltModifier)
{
// alt = will zoom y in
int value = m_zoomingYModel.value();
m_zoomingYModel.setValue(value + 1);
}
break;

case Qt::Key_A:
if (ke->modifiers() & Qt::ControlModifier && m_editMode != EditMode::Strum && m_editMode != EditMode::Knife)
{
Expand Down Expand Up @@ -1461,7 +1504,6 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke)
ke->accept();
break;

case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
Expand Down Expand Up @@ -3221,7 +3263,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe )

// draw vertical quantization lines
// If we're over 100% zoom, we allow all quantization level grids
if (m_zoomingModel.value() <= 3)
if (m_zoomingXModel.value() <= 3)
{
// we're under 100% zoom
// allow quantization grid up to 1/24 for triplets
Expand Down Expand Up @@ -3408,7 +3450,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
float timeSignature =
static_cast<float>(Engine::getSong()->getTimeSigModel().getNumerator()) /
static_cast<float>(Engine::getSong()->getTimeSigModel().getDenominator());
float zoomFactor = m_zoomLevels[m_zoomingModel.value()];
float zoomFactor = m_zoomLevels[m_zoomingXModel.value()];
//the bars which disappears at the left side by scrolling
int leftBars = m_currentPosition * zoomFactor / TimePos::ticksPerBar();
//iterates the visible bars and draw the shading on uneven bars
Expand Down Expand Up @@ -3873,7 +3915,7 @@ void PianoRoll::resizeEvent(QResizeEvent* re)
void PianoRoll::adjustLeftRightScoll(int value)
{
m_leftRightScroll->setValue(m_leftRightScroll->value() -
value * 0.3f / m_zoomLevels[m_zoomingModel.value()]);
value * 0.3f / m_zoomLevels[m_zoomingXModel.value()]);
}


Expand Down Expand Up @@ -3984,7 +4026,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
}
else if( we->modifiers() & Qt::ControlModifier )
{
int z = m_zoomingModel.value();
int z = m_zoomingXModel.value();
if(we->angleDelta().y() > 0)
{
z++;
Expand All @@ -3993,7 +4035,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
{
z--;
}
z = qBound( 0, z, m_zoomingModel.size() - 1 );
z = qBound( 0, z, m_zoomingXModel.size() - 1 );

int x = (pos.x() - m_whiteKeyWidth) * TimePos::ticksPerBar();
// ticks based on the mouse x-position where the scroll wheel was used
Expand All @@ -4003,7 +4045,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
// scroll so the tick "selected" by the mouse x doesn't move on the screen
m_leftRightScroll->setValue(m_leftRightScroll->value() + ticks - newTicks);
// update combobox with zooming-factor
m_zoomingModel.setValue( z );
m_zoomingXModel.setValue( z );
}

// FIXME: Reconsider if determining orientation is necessary in Qt6.
Expand Down Expand Up @@ -4588,8 +4630,23 @@ void PianoRoll::pasteNotes()
}
}

void PianoRoll::duplicateNotes()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like regulus said, there's no need for duplicate since #7873 does that better

{
NoteVector selected_notes = getSelectedNotes();
clearSelectedNotes();

if( ! selected_notes.empty() )
{
for( const Note *note : selected_notes)
{
Note new_note( *note );
new_note.setPos( note->pos() );
new_note.setSelected( true );

m_midiClip->addNote( new_note, false );
}
}
}

//Return false if no notes are deleted
bool PianoRoll::deleteSelectedNotes()
Expand Down Expand Up @@ -4704,13 +4761,13 @@ void PianoRoll::updatePositionStepRecording( const TimePos & t )

void PianoRoll::zoomingChanged()
{
m_ppb = m_zoomLevels[m_zoomingModel.value()] * DEFAULT_PR_PPB;
m_ppb = m_zoomLevels[m_zoomingXModel.value()] * DEFAULT_PR_PPB;

assert( m_ppb > 0 );

m_timeLine->setPixelsPerBar( m_ppb );
m_stepRecorderWidget.setPixelsPerBar( m_ppb );
m_positionLine->zoomChange(m_zoomLevels[m_zoomingModel.value()]);
m_positionLine->zoomChange(m_zoomLevels[m_zoomingXModel.value()]);

update();
}
Expand Down Expand Up @@ -4974,18 +5031,22 @@ PianoRollWindow::PianoRollWindow() :

auto pasteAction = new QAction(embed::getIconPixmap("edit_paste"), tr("Paste (%1+V)").arg(UI_CTRL_KEY), this);

auto duplicateAction = new QAction(embed::getIconPixmap("square_square"), tr("Duplicate (%1+D)").arg(UI_CTRL_KEY), this);

cutAction->setShortcut(keySequence(Qt::CTRL, Qt::Key_X));
copyAction->setShortcut(keySequence(Qt::CTRL, Qt::Key_C));
pasteAction->setShortcut(keySequence(Qt::CTRL, Qt::Key_V));
duplicateAction->setShortcut(keySequence(Qt::CTRL, Qt::Key_D));

connect( cutAction, SIGNAL(triggered()), m_editor, SLOT(cutSelectedNotes()));
connect( copyAction, SIGNAL(triggered()), m_editor, SLOT(copySelectedNotes()));
connect( pasteAction, SIGNAL(triggered()), m_editor, SLOT(pasteNotes()));
connect( duplicateAction, SIGNAL(triggered()), m_editor, SLOT(duplicateNotes()));

copyPasteActionsToolBar->addAction( cutAction );
copyPasteActionsToolBar->addAction( copyAction );
copyPasteActionsToolBar->addAction( pasteAction );

copyPasteActionsToolBar->addAction( duplicateAction);

DropToolBar *timeLineToolBar = addDropToolBarToTop( tr( "Timeline controls" ) );
m_editor->m_timeLine->addToolButtons( timeLineToolBar );
Expand Down Expand Up @@ -5025,6 +5086,10 @@ PianoRollWindow::PianoRollWindow() :
connect(reverseAction, &QAction::triggered, [this](){ m_editor->reverseNotes(); });
reverseAction->setShortcut(keySequence(Qt::SHIFT, Qt::Key_R));

auto flipAction = new QAction(embed::getIconPixmap("flip_y"), tr("Flip Notes"), noteToolsButton);
connect(flipAction, &QAction::triggered, [this](){ m_editor->flipNotes(); });
flipAction->setShortcut(keySequence(Qt::SHIFT, Qt::Key_V));

noteToolsButton->addAction(glueAction);
noteToolsButton->addAction(knifeAction);
noteToolsButton->addAction(strumAction);
Expand All @@ -5033,6 +5098,7 @@ PianoRollWindow::PianoRollWindow() :
noteToolsButton->addAction(minLengthAction);
noteToolsButton->addAction(maxLengthAction);
noteToolsButton->addAction(reverseAction);
noteToolsButton->addAction(flipAction);

notesActionsToolBar->addWidget(noteToolsButton);

Expand All @@ -5045,7 +5111,7 @@ PianoRollWindow::PianoRollWindow() :
zoom_lbl->setPixmap( embed::getIconPixmap( "zoom_x" ) );

m_zoomingComboBox = new ComboBox( m_toolBar );
m_zoomingComboBox->setModel( &m_editor->m_zoomingModel );
m_zoomingComboBox->setModel( &m_editor->m_zoomingXModel );
m_zoomingComboBox->setFixedSize( 64, ComboBox::DEFAULT_HEIGHT );
m_zoomingComboBox->setToolTip( tr( "Horizontal zooming") );

Expand Down
13 changes: 13 additions & 0 deletions src/gui/editors/SongEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,19 @@ void SongEditor::keyPressEvent( QKeyEvent * ke )
{
m_zoomingModel->reset();
}
else if( ke->key() == Qt::Key_Minus && ke->modifiers() & Qt::ControlModifier )
{
// ctrl - will zoom out
int value = m_zoomingModel->value();
m_zoomingModel->setValue(value - 10);
}

else if ( ke->key() == Qt::Key_Equal && ke->modifiers() & Qt::ControlModifier)
{
// ctrl = will zoom in
int value = m_zoomingModel->value();
m_zoomingModel->setValue(value + 10);
}
else
{
QWidget::keyPressEvent(ke);
Expand Down
26 changes: 26 additions & 0 deletions src/tracks/MidiClip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,32 @@ void MidiClip::setStep( int step, bool enabled )
}


void MidiClip::flipNotes(const NoteVector& notes)
{
if (notes.empty()) { return; }

addJournalCheckPoint();

int min = notes.at(0)->key();
int max = notes.at(0)->key();

for (auto note : notes)
{
int key = note->key();
if (key > max) { max = key; }
if (key < min) { min = key; }
}

int sum = min + max;
Comment on lines +314 to +324
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int min = notes.at(0)->key();
int max = notes.at(0)->key();
for (auto note : notes)
{
int key = note->key();
if (key > max) { max = key; }
if (key < min) { min = key; }
}
int sum = min + max;
auto bounds = boundsForNotes(notes)
int sum = bounds->lowest + bounds->highest;


for (auto note : notes)
{
note->setKey(sum - note->key());
}

rearrangeAllNotes();
emit dataChanged();
}

void MidiClip::reverseNotes(const NoteVector& notes)
{
Expand Down