changed the way selection works, and the general editing feel of piano roll. See ChangeLog for more details.

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1837 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Andrew Kelley
2008-11-13 20:12:57 +00:00
parent e609b6fcc7
commit be67937c63
8 changed files with 310 additions and 44 deletions

View File

@@ -14,6 +14,10 @@ Javier Serrano Polo
<jasp00/at/terra/dot/es>
development
Andrew Kelley
<superjoe30/at/gmail/dot/com>
development
Andreas Brandmaier
<andy/at/brandmaier/dot/de>
BitInvader plugin

View File

@@ -1,3 +1,26 @@
2008-11-13 Andrew Kelley <superjoe30/at/gmail/dot/com>
* include/piano_roll.h
* src/gui/piano_roll.cpp
- changed the way selection works
- you can select any combination of notes
- delete any combination of notes
- move multiple notes at once
- resize multiple notes at once
- etc
- hold alt to disable quantization
* include/note.h
* src/core/note.cpp
- added m_selected so we know if the note is selected or not
- added operator< so we can sort notes vector by start time
* include/pattern.h
* src/tracks/pattern.cpp
added rearrangeAllNotes for when we move multiple notes in the piano roll
* AUTHORS
hope you don't mind :-)
2008-11-10 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* src/core/track.cpp:
@@ -25,7 +48,7 @@
2008-11-10 Andrew Kelley <superjoe30/at/gmail/dot/com>
* src/gui/piano_roll.h:
* include/piano_roll.h:
* src/gui/piano_roll.cpp:
- made it so you can hold right click and drag around to delete notes
- changed ctrl+click from opening automation window to shift+click

View File

@@ -90,7 +90,8 @@ public:
detuningHelper * _detuning = NULL );
note( const note & _note );
virtual ~note();
void setSelected( const bool selected );
void setLength( const midiTime & _length );
void setPos( const midiTime & _pos );
void setKey( const int _key );
@@ -99,6 +100,16 @@ public:
void quantizeLength( const int _q_grid );
void quantizePos( const int _q_grid );
inline bool operator<(const note & rhs)
{
return m_pos < rhs.pos();
}
inline bool getSelected( void ) const
{
return m_selected;
}
inline midiTime endPos( void ) const
{
const int l = length();
@@ -177,7 +188,7 @@ private:
ChangePosition
} ;*/
bool m_selected; // for piano roll editing
int m_key;
volume m_volume;
panning m_panning;

View File

@@ -74,7 +74,7 @@ public:
note * rearrangeNote( const note * _note_to_proc,
const bool _quant_pos = TRUE );
void rearrangeAllNotes( void );
void clearNotes( void );
inline const noteVector & notes( void )

View File

@@ -250,8 +250,10 @@ private:
bool mouseOverNote( void );
note * noteUnderMouse( void );
noteVector::const_iterator noteIteratorUnderMouse( void );
// turn a selection rectangle into selected notes
void computeSelectedNotes( bool shift );
void clearSelectedNotes( void );
friend class engine;

View File

@@ -48,7 +48,7 @@ note::note( const midiTime & _length, const midiTime & _pos,
{
//saveJournallingState( FALSE );
// setJournalling( FALSE );
setSelected( false );
if( _detuning )
{
m_detuning = sharedObject::ref( _detuning );
@@ -71,6 +71,7 @@ note::note( const note & _note ) :
m_length( _note.m_length ),
m_pos( _note.m_pos )
{
setSelected( false );
m_detuning = sharedObject::ref( _note.m_detuning );
}
@@ -82,7 +83,10 @@ note::~note()
sharedObject::unref( m_detuning );
}
void note::setSelected( const bool selected )
{
m_selected = selected;
}
void note::setLength( const midiTime & _length )

View File

@@ -653,8 +653,27 @@ void pianoRoll::removeSelection( void )
m_selectedTick = 0;
m_selectStartKey = 0;
m_selectedKeys = 0;
}
void pianoRoll::clearSelectedNotes( void )
{
if( m_pattern != NULL )
{
// get note-vector of current pattern
const noteVector & notes = m_pattern->notes();
// will be our iterator in the following loop
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
( *it )->setSelected( false );
++it;
}
}
}
@@ -895,6 +914,7 @@ void pianoRoll::keyReleaseEvent( QKeyEvent * _ke )
switch( _ke->key() )
{
case Qt::Key_Control:
computeSelectedNotes(_ke->modifiers() & Qt::ShiftModifier);
m_editMode = m_ctrlMode;
update();
break;
@@ -1065,6 +1085,8 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
{
++it;
}
}
m_currentNote = *it;
@@ -1098,8 +1120,16 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
// set move-cursor
QCursor c( Qt::SizeAllCursor );
QApplication::setOverrideCursor( c );
}
// if clicked on an unselected note, remove selection
if( ! m_currentNote->getSelected() )
{
clearSelectedNotes();
}
engine::getSong()->setModified();
}
else if( ( _me->buttons() == Qt::RightButton &&
@@ -1135,6 +1165,10 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
m_action = ActionSelectNotes;
play_note = false;
// call mousemove to fix glitch where selection
// appears in wrong spot on mousedown
mouseMoveEvent( _me );
}
else if( _me->button() == Qt::RightButton &&
m_editMode == ModeSelect )
@@ -1183,11 +1217,121 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
}
}
void pianoRoll::computeSelectedNotes(bool shift)
{
if( m_selectStartTick == 0 &&
m_selectedTick == 0 &&
m_selectStartKey == 0 &&
m_selectedKeys == 0 )
{
// don't bother, there's no selection
return;
}
// setup selection-vars
int sel_pos_start = m_selectStartTick;
int sel_pos_end = m_selectStartTick+m_selectedTick;
if( sel_pos_start > sel_pos_end )
{
qSwap<int>( sel_pos_start, sel_pos_end );
}
int sel_key_start = m_selectStartKey - m_startKey + 1;
int sel_key_end = sel_key_start + m_selectedKeys;
if( sel_key_start > sel_key_end )
{
qSwap<int>( sel_key_start, sel_key_end );
}
//int y_base = height() - PR_BOTTOM_MARGIN - m_notesEditHeight - 1;
if( validPattern() == true )
{
const noteVector & notes = m_pattern->notes();
const int visible_keys = ( height() - PR_TOP_MARGIN -
PR_BOTTOM_MARGIN - m_notesEditHeight ) /
KEY_LINE_HEIGHT + 2;
QPolygon volumeHandles;
for( noteVector::const_iterator it = notes.begin();
it != notes.end(); ++it )
{
// make a new selection unless they're holding shift
if( ! shift )
{
( *it )->setSelected( false );
}
Sint32 len_ticks = ( *it )->length();
if( len_ticks == 0 )
{
continue;
}
else if( len_ticks < 0 )
{
len_ticks = 4;
}
const int key = ( *it )->key() - m_startKey + 1;
Sint32 pos_ticks = ( *it )->pos();
int note_width = len_ticks * m_ppt /
midiTime::ticksPerTact();
const int x = ( pos_ticks - m_currentPosition ) *
m_ppt / midiTime::ticksPerTact();
// skip this note if not in visible area at all
if( !( x + note_width >= 0 &&
x <= width() - WHITE_KEY_WIDTH ) )
{
continue;
}
// is the note in visible area?
if( key > 0 && key <= visible_keys )
{
// if the selection even barely overlaps the note
if( key > sel_key_start &&
key <= sel_key_end &&
pos_ticks + len_ticks > sel_pos_start &&
pos_ticks < sel_pos_end )
{
( *it )->setSelected( true );
}
}
}
}
removeSelection();
update();
}
void pianoRoll::mouseReleaseEvent( QMouseEvent * _me )
{
if( _me->button() & Qt::LeftButton &&
m_editMode == ModeSelect &&
m_action == ActionSelectNotes )
{
// select the notes within the selection rectangle and
// then destroy the selection rectangle
computeSelectedNotes( _me->modifiers() & Qt::ShiftModifier );
}
else if( _me->button() & Qt::LeftButton &&
m_action == ActionMoveNote )
{
// we moved one or more notes so they have to be
// moved properly according to new starting-
// time in the note-array of pattern
m_pattern->rearrangeAllNotes();
}
if( validPattern() == true )
{
if( m_action == ActionChangeNoteVolume && m_currentNote != NULL )
@@ -1364,46 +1508,88 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
else if( m_currentNote != NULL &&
_me->buttons() & Qt::LeftButton && m_editMode == ModeDraw )
{
int key_num = getKey( _me->y() );
//int key_num = getKey( _me->y() );
int key_offset = getKey( _me->y() ) - m_currentNote->key();
if( m_action == ActionMoveNote )
{
x -= m_moveXOffset;
}
int pos_ticks = x * midiTime::ticksPerTact() / m_ppt +
m_currentPosition;
if( m_action == ActionMoveNote )
{
// moving note
if( pos_ticks < 0 )
{
pos_ticks = 0;
}
m_currentNote->setPos( midiTime(
pos_ticks ) );
m_currentNote->setKey( key_num );
int pos_ticks_offset = x * midiTime::ticksPerTact() / m_ppt +
m_currentPosition - m_currentNote->pos().getTicks();
// get note-vector of current pattern
const noteVector & notes = m_pattern->notes();
// we moved the note so the note has to be
// moved properly according to new starting-
// time in the note-array of pattern
m_currentNote = m_pattern->rearrangeNote(
m_currentNote );
}
else
// will be our iterator in the following loop
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
// resizing note
int ticks_diff = pos_ticks -
m_currentNote->pos();
if( ticks_diff <= 0 )
if( ( *it )->getSelected() || m_currentNote == *it )
{
ticks_diff = 1;
if( m_action == ActionMoveNote )
{
// moving note
int pos_ticks = midiTime( ( *it )->pos().getTicks()
+ pos_ticks_offset );
int key_num = ( *it )->key() + key_offset;
if( pos_ticks < 0 )
{
pos_ticks = 0;
}
// TODO: upper/lower bound checks on key_num
/*if( key_num < lower bound )
{
key_num = lower bound
}
else if( key_num > upper bound )
{
key_num = upper bound
} */
( *it )->setPos( midiTime(
pos_ticks ) );
( *it )->setKey( key_num );
if( ! ( _me->modifiers() & Qt::AltModifier ) )
{
( *it )->quantizePos( quantization() );
}
}
else
{
// resizing note
//int pos_ticks = midiTime( ( *it )->pos().getTicks()
// + pos_ticks_offset );
//int ticks_diff = pos_ticks -
// m_currentNote->pos();
int ticks_diff = pos_ticks_offset;
if( ticks_diff <= 0 )
{
ticks_diff = 1;
}
( *it )->setLength( midiTime( ticks_diff ) );
if( ! ( _me->modifiers() & Qt::AltModifier ) )
{
( *it )->quantizeLength( quantization() );
}
m_lenOfNewNotes = ( *it )->length();
m_pattern->dataChanged();
}
}
m_currentNote->setLength( midiTime( ticks_diff ) );
m_currentNote->quantizeLength( quantization() );
m_lenOfNewNotes = m_currentNote->length();
m_pattern->dataChanged();
++it;
}
engine::getSong()->setModified();
}
@@ -2099,7 +2285,9 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
// is the note in visible area?
if( key > 0 && key <= visible_keys )
{
bool is_selected = false;
/* changing the way selection works
bool is_selected = false;
// if we're in move-mode, we may only draw notes
// in selected area, that have originally been
// selected and not notes that are now in
@@ -2122,13 +2310,14 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
{
is_selected = true;
}
*/
// we've done and checked all, lets draw the
// we've done and checked all, let's draw the
// note
drawNoteRect( p, x + WHITE_KEY_WIDTH,
y_base - key * KEY_LINE_HEIGHT,
note_width,
is_selected,
( *it )->getSelected(),
( *it )->length() < 0 );
}
// draw volume-line of note
@@ -2716,7 +2905,34 @@ void pianoRoll::deleteSelectedNotes( void )
{
return;
}
bool update_after_delete = false;
// get note-vector of current pattern
const noteVector & notes = m_pattern->notes();
// will be our iterator in the following loop
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
if( ( *it )->getSelected() )
{
// delete this note
m_pattern->removeNote( ( *it ) );
update_after_delete = true;
// start over, make sure we get all the notes
it = notes.begin();
}
else
{
++it;
}
}
/*
noteVector selected_notes;
getSelectedNotes( selected_notes );
@@ -2726,7 +2942,7 @@ void pianoRoll::deleteSelectedNotes( void )
{
m_pattern->removeNote( selected_notes.front() );
selected_notes.erase( selected_notes.begin() );
}
} */
if( update_after_delete == true )
{
@@ -2734,6 +2950,7 @@ void pianoRoll::deleteSelectedNotes( void )
update();
engine::getSongEditor()->update();
}
}

View File

@@ -269,7 +269,12 @@ note * pattern::rearrangeNote( const note * _note_to_proc,
return( addNote( copy_of_note, _quant_pos ) );
}
void pattern::rearrangeAllNotes( void )
{
// sort notes by start time
qSort(m_notes.begin(), m_notes.end());
}
void pattern::clearNotes( void )