() )
- {
- if( w->parent() == m_descriptionWidget )
- {
- l->addWidget( w );
- }
- }
- l->setSizeConstraint( QLayout::SetFixedSize );
+ QHBoxLayout *hbox = new QHBoxLayout( m_descriptionWidget );
+
+ Plugin::Descriptor const & descriptor = *( m_currentSelection.desc );
+
+ if ( descriptor.logo )
+ {
+ QLabel *logoLabel = new QLabel( m_descriptionWidget );
+ logoLabel->setPixmap( descriptor.logo->pixmap() );
+ logoLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ hbox->addWidget( logoLabel );
+ hbox->setAlignment( logoLabel, Qt::AlignTop);
+ }
+
+ QWidget *textualInfoWidget = new QWidget( m_descriptionWidget );
+
+ hbox->addWidget(textualInfoWidget);
+
+ QVBoxLayout * textWidgetLayout = new QVBoxLayout( textualInfoWidget);
+ textWidgetLayout->setMargin( 4 );
+ textWidgetLayout->setSpacing( 0 );
+
+ std::string stdName(descriptor.name);
+ if ( stdName != "ladspaeffect" )
+ {
+ QLabel *label = new QLabel(m_descriptionWidget);
+ QString labelText = "" + tr("Name") + ": " + QString::fromUtf8(descriptor.displayName) + "
";
+ labelText += "" + tr("Description") + ": " + QString::fromUtf8(descriptor.description) + "
";
+ labelText += "" + tr("Author") + ": " + QString::fromUtf8(descriptor.author) + "
";
+
+ label->setText(labelText);
+ textWidgetLayout->addWidget(label);
+ }
+
+ if ( m_currentSelection.desc->subPluginFeatures )
+ {
+ QWidget *subWidget = new QWidget(textualInfoWidget);
+ QVBoxLayout * subLayout = new QVBoxLayout( subWidget );
+ subLayout->setMargin( 4 );
+ subLayout->setSpacing( 0 );
+ m_currentSelection.desc->subPluginFeatures->
+ fillDescriptionWidget( subWidget, &m_currentSelection );
+ foreach( QWidget * w, subWidget->findChildren() )
+ {
+ if( w->parent() == subWidget )
+ {
+ subLayout->addWidget( w );
+ }
+ }
+
+ textWidgetLayout->addWidget(subWidget);
+ }
+
+ ui->scrollArea->setWidget( m_descriptionWidget );
m_descriptionWidget->show();
}
}
diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp
index 9fffa92053b..e213d801c4d 100644
--- a/src/gui/FileBrowser.cpp
+++ b/src/gui/FileBrowser.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include "FileBrowser.h"
#include "BBTrackContainer.h"
@@ -97,6 +98,10 @@ FileBrowser::FileBrowser(const QString & directories, const QString & filter,
addContentWidget( ops );
+ // Whenever the FileBrowser has focus, Ctrl+F should direct focus to its filter box.
+ QShortcut *filterFocusShortcut = new QShortcut( QKeySequence( QKeySequence::Find ), this, SLOT(giveFocusToFilter()) );
+ filterFocusShortcut->setContext(Qt::WidgetWithChildrenShortcut);
+
reloadTree();
show();
}
@@ -253,7 +258,15 @@ void FileBrowser::reloadTree( void )
filterItems( text );
}
-
+void FileBrowser::giveFocusToFilter()
+{
+ if (!m_filterEdit->hasFocus())
+ {
+ // give focus to filter text box and highlight its text for quick editing if not previously focused
+ m_filterEdit->setFocus();
+ m_filterEdit->selectAll();
+ }
+}
void FileBrowser::addItems(const QString & path )
diff --git a/src/gui/Forms/EffectSelectDialog.ui b/src/gui/Forms/EffectSelectDialog.ui
index a58cd6c8c61..a19233ac8c3 100644
--- a/src/gui/Forms/EffectSelectDialog.ui
+++ b/src/gui/Forms/EffectSelectDialog.ui
@@ -7,7 +7,7 @@
0
0
585
- 547
+ 550
@@ -40,41 +40,20 @@
-
-
-
-
- 0
- 200
-
-
-
-
- 16777215
- 210
-
-
-
- Plugin description
+
+
+ QFrame::NoFrame
-
-
-
-
-
- QFrame::NoFrame
-
-
-
-
- 0
- 0
- 497
- 109
-
-
-
-
-
-
+
+
+
+ 0
+ 0
+ 497
+ 109
+
+
+
-
diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp
index 5e99ca32de0..2a8271048d6 100644
--- a/src/gui/FxMixerView.cpp
+++ b/src/gui/FxMixerView.cpp
@@ -510,6 +510,12 @@ void FxMixerView::keyPressEvent(QKeyEvent * e)
setCurrentFxLine( m_currentFxLine->channelIndex()+1 );
}
break;
+ case Qt::Key_Insert:
+ if ( e->modifiers() & Qt::ShiftModifier )
+ {
+ addNewChannel();
+ }
+ break;
}
}
diff --git a/src/gui/GuiApplication.cpp b/src/gui/GuiApplication.cpp
index 78cf609efb6..4a9b35f73d4 100644
--- a/src/gui/GuiApplication.cpp
+++ b/src/gui/GuiApplication.cpp
@@ -49,6 +49,7 @@ GuiApplication* GuiApplication::instance()
return s_instance;
}
+
GuiApplication::GuiApplication()
{
// Init style and palette
@@ -64,27 +65,60 @@ GuiApplication::GuiApplication()
// Show splash screen
QSplashScreen splashScreen( embed::getIconPixmap( "splash" ) );
splashScreen.show();
- splashScreen.showMessage( MainWindow::tr( "Version %1" ).arg( LMMS_VERSION ),
- Qt::AlignRight | Qt::AlignBottom, Qt::white );
+
+ QHBoxLayout layout;
+ layout.setAlignment(Qt::AlignBottom);
+ splashScreen.setLayout(&layout);
+
+ // Create a left-aligned label for loading progress
+ // & a right-aligned label for version info
+ QLabel loadingProgressLabel;
+ m_loadingProgressLabel = &loadingProgressLabel;
+ QLabel versionLabel(MainWindow::tr( "Version %1" ).arg( LMMS_VERSION ));
+
+ loadingProgressLabel.setAlignment(Qt::AlignLeft);
+ versionLabel.setAlignment(Qt::AlignRight);
+
+ layout.addWidget(&loadingProgressLabel);
+ layout.addWidget(&versionLabel);
+
+ // may have long gaps between future frames, so force update now
+ splashScreen.update();
qApp->processEvents();
+ connect(Engine::inst(), SIGNAL(initProgress(const QString&)),
+ this, SLOT(displayInitProgress(const QString&)));
+
// Init central engine which handles all components of LMMS
Engine::init();
s_instance = this;
+ displayInitProgress(tr("Preparing UI"));
+
m_mainWindow = new MainWindow;
+ connect(m_mainWindow, SIGNAL(initProgress(const QString&)),
+ this, SLOT(displayInitProgress(const QString&)));
+ displayInitProgress(tr("Preparing song editor"));
m_songEditor = new SongEditorWindow(Engine::getSong());
+ displayInitProgress(tr("Preparing mixer"));
m_fxMixerView = new FxMixerView;
+ displayInitProgress(tr("Preparing controller rack"));
m_controllerRackView = new ControllerRackView;
+ displayInitProgress(tr("Preparing project notes"));
m_projectNotes = new ProjectNotes;
+ displayInitProgress(tr("Preparing beat/bassline editor"));
m_bbEditor = new BBEditor(Engine::getBBTrackContainer());
+ displayInitProgress(tr("Preparing piano roll"));
m_pianoRoll = new PianoRollWindow();
+ displayInitProgress(tr("Preparing automation editor"));
m_automationEditor = new AutomationEditorWindow;
m_mainWindow->finalize();
splashScreen.finish(m_mainWindow);
+
+ m_loadingProgressLabel = nullptr;
}
GuiApplication::~GuiApplication()
@@ -92,3 +126,14 @@ GuiApplication::~GuiApplication()
InstrumentTrackView::cleanupWindowCache();
s_instance = nullptr;
}
+
+
+void GuiApplication::displayInitProgress(const QString &msg)
+{
+ Q_ASSERT(m_loadingProgressLabel != nullptr);
+
+ m_loadingProgressLabel->setText(msg);
+ // must force a UI update and process events, as there may be long gaps between processEvents() calls during init
+ m_loadingProgressLabel->repaint();
+ qApp->processEvents();
+}
diff --git a/src/gui/LfoControllerDialog.cpp b/src/gui/LfoControllerDialog.cpp
index b7c3eced790..f13928969f5 100644
--- a/src/gui/LfoControllerDialog.cpp
+++ b/src/gui/LfoControllerDialog.cpp
@@ -50,7 +50,6 @@ const int CD_KNOB_X_SPACING = 32;
const int CD_LFO_SHAPES_X = 6;
const int CD_LFO_SHAPES_Y = 36;
-const int CD_LFO_GRAPH_X = 6;
const int CD_LFO_GRAPH_Y = CD_ENV_KNOBS_LBL_Y+15;
const int CD_LFO_CD_KNOB_Y = CD_LFO_GRAPH_Y-2;
const int CD_LFO_BASE_CD_KNOB_X = CD_LFO_SHAPES_X + 64;
@@ -243,7 +242,6 @@ LfoControllerDialog::LfoControllerDialog( Controller * _model, QWidget * _parent
LfoControllerDialog::~LfoControllerDialog()
{
m_userWaveBtn->disconnect( this );
- //delete m_subWindow;
}
@@ -287,13 +285,6 @@ void LfoControllerDialog::contextMenuEvent( QContextMenuEvent * )
}
-/*
-void lfoControllerDialog::paintEvent( QPaintEvent * _pe )
-{
- QWidget::paintEvent( _pe );
-}
-*/
-
void LfoControllerDialog::modelChanged()
{
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 0c62bf6b4bd..b837a3fa2a6 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
@@ -96,7 +97,9 @@ MainWindow::MainWindow() :
ConfigManager* confMgr = ConfigManager::inst();
+ emit initProgress(tr("Preparing plugin browser"));
sideBar->appendTab( new PluginBrowser( splitter ) );
+ emit initProgress(tr("Preparing file browsers"));
sideBar->appendTab( new FileBrowser(
confMgr->userProjectsDir() + "*" +
confMgr->factoryProjectsDir(),
@@ -150,6 +153,7 @@ MainWindow::MainWindow() :
m_workspace = new QMdiArea( splitter );
// Load background
+ emit initProgress(tr("Loading background artwork"));
QString bgArtwork = ConfigManager::inst()->backgroundArtwork();
QImage bgImage;
if( !bgArtwork.isEmpty() )
@@ -231,12 +235,12 @@ void MainWindow::finalize()
project_menu->addAction( embed::getIconPixmap( "project_new" ),
tr( "&New" ),
this, SLOT( createNewProject() ),
- Qt::CTRL + Qt::Key_N );
+ QKeySequence::New );
project_menu->addAction( embed::getIconPixmap( "project_open" ),
tr( "&Open..." ),
this, SLOT( openProject() ),
- Qt::CTRL + Qt::Key_O );
+ QKeySequence::Open );
m_recentlyOpenedProjectsMenu = project_menu->addMenu(
embed::getIconPixmap( "project_open_recent" ),
@@ -249,7 +253,7 @@ void MainWindow::finalize()
project_menu->addAction( embed::getIconPixmap( "project_save" ),
tr( "&Save" ),
this, SLOT( saveProject() ),
- Qt::CTRL + Qt::Key_S );
+ QKeySequence::Save );
project_menu->addAction( embed::getIconPixmap( "project_saveas" ),
tr( "Save &As..." ),
this, SLOT( saveProjectAs() ),
@@ -288,18 +292,29 @@ void MainWindow::finalize()
QMenu * edit_menu = new QMenu( this );
menuBar()->addMenu( edit_menu )->setText( tr( "&Edit" ) );
- edit_menu->addAction( embed::getIconPixmap( "edit_undo" ),
+ m_undoAction = edit_menu->addAction( embed::getIconPixmap( "edit_undo" ),
tr( "Undo" ),
this, SLOT( undo() ),
- Qt::CTRL + Qt::Key_Z );
- edit_menu->addAction( embed::getIconPixmap( "edit_redo" ),
+ QKeySequence::Undo );
+ m_redoAction = edit_menu->addAction( embed::getIconPixmap( "edit_redo" ),
tr( "Redo" ),
this, SLOT( redo() ),
- Qt::CTRL + Qt::Key_Y );
+ QKeySequence::Redo );
+ // Ensure that both (Ctrl+Y) and (Ctrl+Shift+Z) activate redo shortcut regardless of OS defaults
+ if (QKeySequence(QKeySequence::Redo) != QKeySequence(Qt::CTRL + Qt::Key_Y))
+ {
+ new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_Y ), this, SLOT(redo()) );
+ }
+ if (QKeySequence(QKeySequence::Redo) != QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z ))
+ {
+ new QShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_Z ), this, SLOT(redo()) );
+ }
+
edit_menu->addSeparator();
edit_menu->addAction( embed::getIconPixmap( "setup_general" ),
tr( "Settings" ),
this, SLOT( showSettingsDialog() ) );
+ connect( edit_menu, SIGNAL(aboutToShow()), this, SLOT(updateUndoRedoButtons()) );
m_viewMenu = new QMenu( this );
menuBar()->addMenu( m_viewMenu )->setText( tr( "&View" ) );
@@ -385,7 +400,7 @@ void MainWindow::finalize()
ToolButton * project_open_recent = new ToolButton(
embed::getIconPixmap( "project_open_recent" ),
- tr( "Recently opened project" ),
+ tr( "Recently opened projects" ),
this, SLOT( emptySlot() ), m_toolBar );
project_open_recent->setMenu( m_recentlyOpenedProjectsMenu );
project_open_recent->setPopupMode( ToolButton::InstantPopup );
@@ -1182,6 +1197,14 @@ void MainWindow::updatePlayPauseIcons()
}
+void MainWindow::updateUndoRedoButtons()
+{
+ // when the edit menu is shown, grey out the undo/redo buttons if there's nothing to undo/redo
+ // else, un-grey them
+ m_undoAction->setEnabled(Engine::projectJournal()->canUndo());
+ m_redoAction->setEnabled(Engine::projectJournal()->canRedo());
+}
+
void MainWindow::undo()
diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp
index 2db16438408..29abbfc7cbb 100644
--- a/src/gui/TrackContainerView.cpp
+++ b/src/gui/TrackContainerView.cpp
@@ -157,45 +157,48 @@ void TrackContainerView::removeTrackView( TrackView * _tv )
-void TrackContainerView::moveTrackViewUp( TrackView * _tv )
+void TrackContainerView::moveTrackView( TrackView * trackView, int indexTo )
{
- for( int i = 1; i < m_trackViews.size(); ++i )
- {
- TrackView * t = m_trackViews[i];
- if( t == _tv )
- {
- BBTrack::swapBBTracks( t->getTrack(),
- m_trackViews[i - 1]->getTrack() );
- m_scrollLayout->removeWidget( t );
- m_scrollLayout->insertWidget( i - 1, t );
- qSwap( m_tc->m_tracks[i-1], m_tc->m_tracks[i] );
- m_trackViews.swap( i - 1, i );
- realignTracks();
- break;
- }
- }
+ // Can't move out of bounds
+ if ( indexTo >= m_trackViews.size() || indexTo < 0 ) { return; }
+
+ // Does not need to move to itself
+ int indexFrom = m_trackViews.indexOf( trackView );
+ if ( indexFrom == indexTo ) { return; }
+
+ BBTrack::swapBBTracks( trackView->getTrack(),
+ m_trackViews[indexTo]->getTrack() );
+
+ m_scrollLayout->removeWidget( trackView );
+ m_scrollLayout->insertWidget( indexTo, trackView );
+
+ Track * track = m_tc->m_tracks[indexFrom];
+
+ m_tc->m_tracks.remove( indexFrom );
+ m_tc->m_tracks.insert( indexTo, track );
+ m_trackViews.move( indexFrom, indexTo );
+
+ realignTracks();
}
-void TrackContainerView::moveTrackViewDown( TrackView * _tv )
+void TrackContainerView::moveTrackViewUp( TrackView * trackView )
{
- for( int i = 0; i < m_trackViews.size()-1; ++i )
- {
- TrackView * t = m_trackViews[i];
- if( t == _tv )
- {
- BBTrack::swapBBTracks( t->getTrack(),
- m_trackViews[i + 1]->getTrack() );
- m_scrollLayout->removeWidget( t );
- m_scrollLayout->insertWidget( i + 1, t );
- qSwap( m_tc->m_tracks[i], m_tc->m_tracks[i+1] );
- m_trackViews.swap( i, i + 1 );
- realignTracks();
- break;
- }
- }
+ int index = m_trackViews.indexOf( trackView );
+
+ moveTrackView( trackView, index - 1 );
+}
+
+
+
+
+void TrackContainerView::moveTrackViewDown( TrackView * trackView )
+{
+ int index = m_trackViews.indexOf( trackView );
+
+ moveTrackView( trackView, index + 1 );
}
void TrackContainerView::scrollToTrackView( TrackView * _tv )
@@ -242,11 +245,18 @@ void TrackContainerView::realignTracks()
-void TrackContainerView::createTrackView( Track * _t )
+TrackView * TrackContainerView::createTrackView( Track * _t )
{
//m_tc->addJournalCheckPoint();
- _t->createView( this );
+ // Avoid duplicating track views
+ for( trackViewList::iterator it = m_trackViews.begin();
+ it != m_trackViews.end(); ++it )
+ {
+ if ( ( *it )->getTrack() == _t ) { return ( *it ); }
+ }
+
+ return _t->createView( this );
}
diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp
index 3c31b789511..8d02ddcf14d 100644
--- a/src/gui/editors/PianoRoll.cpp
+++ b/src/gui/editors/PianoRoll.cpp
@@ -2434,7 +2434,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
{
if( m_moveBoundaryLeft + off_ticks < 0 )
{
- off_ticks += 0 - (off_ticks + m_moveBoundaryLeft);
+ off_ticks -= (off_ticks + m_moveBoundaryLeft);
}
if( m_moveBoundaryTop + off_key > NumKeys )
{
@@ -2442,92 +2442,161 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
}
if( m_moveBoundaryBottom + off_key < 0 )
{
- off_key += 0 - (m_moveBoundaryBottom + off_key);
+ off_key -= (m_moveBoundaryBottom + off_key);
}
}
- int shift_offset = 0;
- int shift_ref_pos = -1;
// get note-vector of current pattern
const NoteVector & notes = m_pattern->notes();
- // will be our iterator in the following loop
- NoteVector::ConstIterator it = notes.begin();
-
- int sNotes = selectionCount();
- while( it != notes.end() )
+ if (m_action == ActionMoveNote)
+ {
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
+ {
+ Note *note = *it;
+ if( note->selected() )
+ {
+ if( ! ( shift && ! m_startedWithShift ) )
+ {
+ // moving note
+ int pos_ticks = note->oldPos().getTicks() + off_ticks;
+ int key_num = note->oldKey() + off_key;
+
+ // ticks can't be negative
+ pos_ticks = qMax(0, pos_ticks);
+ // upper/lower bound checks on key_num
+ key_num = qMax(0, key_num);
+ key_num = qMin(key_num, NumKeys);
+
+ note->setPos( MidiTime( pos_ticks ) );
+ note->setKey( key_num );
+ }
+ else if( shift && ! m_startedWithShift )
+ {
+ // quick resize, toggled by holding shift after starting a note move, but not before
+ int ticks_new = note->oldLength().getTicks() + off_ticks;
+ if( ticks_new <= 0 )
+ {
+ ticks_new = 1;
+ }
+ note->setLength( MidiTime( ticks_new ) );
+ m_lenOfNewNotes = note->length();
+ }
+ }
+ }
+ }
+ else if (m_action == ActionResizeNote)
{
- Note *note = *it;
- const int pos = note->pos().getTicks();
-
// When resizing notes:
+ // If shift is not pressed, resize the selected notes but do not rearrange them
// If shift is pressed we resize and rearrange only the selected notes
// If shift + ctrl then we also rearrange all posterior notes (sticky)
// If shift is pressed but only one note is selected, apply sticky
- if( m_action == ActionResizeNote && shift &&
- ( note->selected() || ctrl || sNotes == 1 ) )
+
+ if (shift)
{
- int shifted_pos = note->oldPos().getTicks() + shift_offset;
- if( shifted_pos && pos == shift_ref_pos )
+ // Algorithm:
+ // Relative to the starting point of the left-most selected note,
+ // all selected note start-points and *endpoints* (not length) should be scaled by a calculated factor.
+ // This factor is such that the endpoint of the note whose handle is being dragged should lie under the cursor.
+ // first, determine the start-point of the left-most selected note:
+ int stretchStartTick = -1;
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
{
- shifted_pos -= off_ticks;
+ Note *note = *it;
+ if (note->selected() && (stretchStartTick < 0 || note->oldPos().getTicks() < stretchStartTick))
+ {
+ stretchStartTick = note->oldPos().getTicks();
+ }
}
- note->setPos( MidiTime( shifted_pos ) );
- }
-
- if( note->selected() )
- {
- if( m_action == ActionMoveNote && ! ( shift && ! m_startedWithShift ) )
+ // determine the ending tick of the right-most selected note
+ Note *posteriorNote = nullptr;
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
{
- // moving note
- int pos_ticks = note->oldPos().getTicks() + off_ticks;
- int key_num = note->oldKey() + off_key;
-
- // ticks can't be negative
- pos_ticks = qMax(0, pos_ticks);
- // upper/lower bound checks on key_num
- key_num = qMax(0, key_num);
- key_num = qMin(key_num, NumKeys);
-
- note->setPos( MidiTime( pos_ticks ) );
- note->setKey( key_num );
+ Note *note = *it;
+ if (note->selected() && (posteriorNote == nullptr ||
+ note->oldPos().getTicks() + note->oldLength().getTicks() >
+ posteriorNote->oldPos().getTicks() + posteriorNote->oldLength().getTicks()))
+ {
+ posteriorNote = note;
+ }
}
- else if( m_action == ActionResizeNote )
+ int posteriorEndTick = posteriorNote->pos().getTicks() + posteriorNote->length().getTicks();
+ // end-point of the note whose handle is being dragged:
+ int stretchEndTick = m_currentNote->oldPos().getTicks() + m_currentNote->oldLength().getTicks();
+ // Calculate factor by which to scale the start-point and end-point of all selected notes
+ float scaleFactor = (float)(stretchEndTick - stretchStartTick + off_ticks) / qMax(1, stretchEndTick - stretchStartTick);
+ scaleFactor = qMax(0.0f, scaleFactor);
+
+ // process all selected notes & determine how much the endpoint of the right-most note was shifted
+ int posteriorDeltaThisFrame = 0;
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
{
- // resizing note
- int ticks_new = note->oldLength().getTicks() + off_ticks;
- if( ticks_new <= 0 )
+ Note *note = *it;
+ if(note->selected())
{
- ticks_new = 1;
+ // scale relative start and end positions by scaleFactor
+ int newStart = stretchStartTick + scaleFactor *
+ (note->oldPos().getTicks() - stretchStartTick);
+ int newEnd = stretchStartTick + scaleFactor *
+ (note->oldPos().getTicks()+note->oldLength().getTicks() - stretchStartTick);
+ // if not holding alt, quantize the offsets
+ if(!alt)
+ {
+ // quantize start time
+ int oldStart = note->oldPos().getTicks();
+ int startDiff = newStart - oldStart;
+ startDiff = floor(startDiff / quantization()) * quantization();
+ newStart = oldStart + startDiff;
+ // quantize end time
+ int oldEnd = oldStart + note->oldLength().getTicks();
+ int endDiff = newEnd - oldEnd;
+ endDiff = floor(endDiff / quantization()) * quantization();
+ newEnd = oldEnd + endDiff;
+ }
+ int newLength = qMax(1, newEnd-newStart);
+ if (note == posteriorNote)
+ {
+ posteriorDeltaThisFrame = (newStart+newLength) -
+ (note->pos().getTicks() + note->length().getTicks());
+ }
+ note->setLength( MidiTime(newLength) );
+ note->setPos( MidiTime(newStart) );
+
+ m_lenOfNewNotes = note->length();
}
- else if( shift )
+ }
+ if (ctrl || selectionCount() == 1)
+ {
+ // if holding ctrl or only one note is selected, reposition posterior notes
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
{
- // when holding shift: update the offset used to shift
- // the following notes
- if( pos > shift_ref_pos )
+ Note *note = *it;
+ if (!note->selected() && note->pos().getTicks() >= posteriorEndTick)
{
- shift_offset += off_ticks;
- shift_ref_pos = pos;
+ int newStart = note->pos().getTicks() + posteriorDeltaThisFrame;
+ note->setPos( MidiTime(newStart) );
}
}
- note->setLength( MidiTime( ticks_new ) );
-
- m_lenOfNewNotes = note->length();
}
- else if( m_action == ActionMoveNote && ( shift && ! m_startedWithShift ) )
+ }
+ else
+ {
+ // shift is not pressed; stretch length of selected notes but not their position
+ for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it )
{
- // quick resize, toggled by holding shift after starting a note move, but not before
- int ticks_new = note->oldLength().getTicks() + off_ticks;
- if( ticks_new <= 0 )
+ Note *note = *it;
+ if (note->selected())
{
- ticks_new = 1;
+ int newLength = note->oldLength() + off_ticks;
+ newLength = qMax(1, newLength);
+ note->setLength( MidiTime(newLength) );
+
+ m_lenOfNewNotes = note->length();
}
- note->setLength( MidiTime( ticks_new ) );
- m_lenOfNewNotes = note->length();
}
}
- ++it;
}
m_pattern->dataChanged();