piano roll improvements

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1860 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Andrew Kelley
2008-11-30 05:31:05 +00:00
parent 96bad01415
commit c50ca0eb9b
5 changed files with 194 additions and 56 deletions

View File

@@ -1,3 +1,21 @@
2008-11-29 Andrew Kelley <superjoe30/at/gmail/dot/com>
* include/piano_roll.h:
* src/gui/piano_roll.cpp:
- when you draw a note it clears the selection and selects the new note
- removed the move tool, it's irrelevant now
- when dragging right click around to delete notes, show the eraser icon
- when moving a selection around, show the move icon
- ctrl+ up / ctrl+down arrow key to move everything up/down 12 semitones
- shift+left / shift+right to move all notes to the left or right
- make arrow keys left+right scroll
* src/core/note.cpp:
got rid of warnings for copy constructor
* TODO:
you know... todo stuff.
2008-11-29 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* include/resources_tree_view.h:

10
TODO
View File

@@ -41,6 +41,7 @@
- Swedish
- Norwegian
- Greece
- Elvish
- ...
@@ -51,12 +52,11 @@
- add FLAC as export-format?
Andrew Kelley's todo:
- when you draw a note, if there's a selection it should clear it
- piano roll, copy and paste notes
- remove the move tool, it's irrelevant now
- don't play notes when you click on one if the song is already playing
- humanizing tool for piano roll (add a tools menu to piano roll and put some of the tools with keyboard shortcuts on there)
- dragging a note below the automation level messes up dragging it's weird and glitchy fix it
- holding control and shift shouldn't bring up the automation window
- shift+drag to copy one or more notes
- when dragging right click around to delete notes, show the eraser icon
- moving a group of notes shouldn't crunch them together if brought to boundary conditions
- moving a group with an unquantized note will quantize that note when you move the selection (this is bad)
- undo/redo for piano roll
@@ -69,6 +69,6 @@ Andrew Kelley's todo:
- make the menu for a channel happen when you right click, instead of renaming, and make the midi input a top-level menu item
- segfault on quit
- recording automation
- dragging a note below the automation level messes up dragging it's weird and glitchy fix it
- adding/removing steps to the beat+bassline editor is awkward
- the 'add beat+bassline' button in the beat+bassline editor is misleading - I say we remove it and rely on the song editor to add beat+basslines
- make it so that 3xosc notes don't max out

View File

@@ -166,8 +166,14 @@ private:
virtual ~pianoRoll();
midiTime newNoteLen( void ) const;
void shiftPos(int amount);
void shiftSemiTone(int amount);
bool isSelection() const;
static const int cm_scrollAmtHoriz = 10;
static const int cm_scrollAmtVert = 1;
static QPixmap * s_whiteKeyBigPm;
static QPixmap * s_whiteKeySmallPm;
static QPixmap * s_blackKeyPm;
@@ -190,7 +196,6 @@ private:
toolButton * m_drawButton;
toolButton * m_eraseButton;
toolButton * m_selectButton;
toolButton * m_moveButton;
toolButton * m_cutButton;
toolButton * m_copyButton;
@@ -239,7 +244,9 @@ private:
editModes m_editMode;
editModes m_ctrlMode; // mode they were in before they hit ctrl
bool m_mouseDownLeft; //true if left click is being held down
bool m_mouseDownRight; //true if right click is being held down
timeLine * m_timeLine;
bool m_scrollBack;

View File

@@ -65,12 +65,12 @@ note::note( const midiTime & _length, const midiTime & _pos,
note::note( const note & _note ) :
serializingObject( _note ),
m_selected( _note.m_selected ),
m_key( _note.m_key),
m_volume( _note.m_volume ),
m_panning( _note.m_panning ),
m_length( _note.m_length ),
m_pos( _note.m_pos ),
m_selected( _note.m_selected )
m_pos( _note.m_pos )
{
m_detuning = sharedObject::ref( _note.m_detuning );
}

View File

@@ -147,6 +147,8 @@ pianoRoll::pianoRoll( void ) :
m_startKey( INITIAL_START_KEY ),
m_lastKey( 0 ),
m_editMode( ModeDraw ),
m_mouseDownLeft( false ),
m_mouseDownRight( false ),
m_scrollBack( false )
{
// init pixmaps
@@ -291,17 +293,11 @@ pianoRoll::pianoRoll( void ) :
m_toolBar );
m_selectButton->setCheckable( true );
m_moveButton = new toolButton( embed::getIconPixmap( "edit_move" ),
tr( "Move selection mode (Shift+M)" ),
this, SLOT( moveButtonToggled() ),
m_toolBar );
m_moveButton->setCheckable( true );
QButtonGroup * tool_button_group = new QButtonGroup( this );
tool_button_group->addButton( m_drawButton );
tool_button_group->addButton( m_eraseButton );
tool_button_group->addButton( m_selectButton );
tool_button_group->addButton( m_moveButton );
tool_button_group->setExclusive( true );
m_drawButton->setWhatsThis(
@@ -320,11 +316,6 @@ pianoRoll::pianoRoll( void ) :
"if you want to cut, copy, paste, delete or move "
"notes. You can also press 'Shift+S' on your keyboard "
"to activate this mode." ) );
m_moveButton->setWhatsThis(
tr( "Click here and move-mode will be activated. In this "
"mode you can move the notes you selected in select-"
"mode. You can also press 'Shift+M' on your keyboard "
"to activate this mode." ) );
m_cutButton = new toolButton( embed::getIconPixmap( "edit_cut" ),
tr( "Cut selected notes (Ctrl+X)" ),
@@ -432,7 +423,6 @@ pianoRoll::pianoRoll( void ) :
tb_layout->addWidget( m_drawButton );
tb_layout->addWidget( m_eraseButton );
tb_layout->addWidget( m_selectButton );
tb_layout->addWidget( m_moveButton );
tb_layout->addSpacing( 10 );
tb_layout->addWidget( m_cutButton );
tb_layout->addWidget( m_copyButton );
@@ -691,8 +681,58 @@ void pianoRoll::closeEvent( QCloseEvent * _ce )
_ce->ignore();
}
void pianoRoll::shiftSemiTone(int amount) // shift notes by amount semitones
{
bool useAllNotes = ! isSelection();
const noteVector & notes = m_pattern->notes();
for( noteVector::const_iterator it = notes.begin(); it != notes.end(); ++it)
{
// if none are selected, move all notes, otherwise
// only move selected notes
if( useAllNotes || ( *it )->getSelected() )
{
( *it )->setKey( ( *it )->key() + amount );
}
}
// we modified the song
update();
engine::getSongEditor()->update();
}
void pianoRoll::shiftPos(int amount) //shift notes pos by amount
{
bool useAllNotes = ! isSelection();
const noteVector & notes = m_pattern->notes();
for( noteVector::const_iterator it = notes.begin(); it != notes.end(); ++it)
{
// if none are selected, move all notes, otherwise
// only move selected notes
if( useAllNotes || ( *it )->getSelected() )
{
( *it )->setPos( ( *it )->pos() + amount );
}
}
// we modified the song
update();
engine::getSongEditor()->update();
}
bool pianoRoll::isSelection() const // are any notes selected?
{
const noteVector & notes = m_pattern->notes();
for( noteVector::const_iterator it = notes.begin(); it != notes.end(); ++it)
{
if( ( *it )->getSelected() )
{
return true;
}
}
return false;
}
void pianoRoll::keyPressEvent( QKeyEvent * _ke )
{
@@ -711,28 +751,84 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke )
switch( _ke->key() )
{
case Qt::Key_Up:
m_topBottomScroll->setValue(
m_topBottomScroll->value() - 1 );
if( _ke->modifiers() & Qt::ControlModifier )
{
// shift selection up an octave
// if nothing selected, shift _everything_
shiftSemiTone( +12 );
}
else
{
// scroll
m_topBottomScroll->setValue(
m_topBottomScroll->value() - cm_scrollAmtVert );
}
break;
case Qt::Key_Down:
m_topBottomScroll->setValue(
m_topBottomScroll->value() + 1 );
if( _ke->modifiers() & Qt::ControlModifier )
{
// shift selection down an octave
// if nothing selected, shift _everything_
shiftSemiTone( -12 );
}
else
{
// scroll
m_topBottomScroll->setValue(
m_topBottomScroll->value() + cm_scrollAmtVert );
}
break;
case Qt::Key_Left:
{
if( ( m_timeLine->pos() -= 16 ) < 0 )
if( _ke->modifiers() & Qt::ControlModifier )
{
m_timeLine->pos().setTicks( 0 );
// move time ticker
if( ( m_timeLine->pos() -= 16 ) < 0 )
{
m_timeLine->pos().setTicks( 0 );
}
m_timeLine->updatePosition();
}
else if( _ke->modifiers() & Qt::ShiftModifier )
{
// move notes
bool quantized = ! (_ke->modifiers() & Qt::AltModifier);
int amt = quantized ? quantization() : 1;
shiftPos( -amt );
}
else
{
// scroll
m_leftRightScroll->setValue(
m_leftRightScroll->value() - cm_scrollAmtHoriz );
}
m_timeLine->updatePosition();
break;
}
case Qt::Key_Right:
{
m_timeLine->pos() += 16;
m_timeLine->updatePosition();
if( _ke->modifiers() & Qt::ControlModifier )
{
// move time ticker
m_timeLine->pos() += 16;
m_timeLine->updatePosition();
}
else if( _ke->modifiers() & Qt::ShiftModifier )
{
// move notes
bool quantized = ! (_ke->modifiers() & Qt::AltModifier);
int amt = quantized ? quantization() : 1;
shiftPos( +amt );
}
else
{
// scroll
m_leftRightScroll->setValue(
m_leftRightScroll->value() + cm_scrollAmtHoriz );
}
break;
}
@@ -815,17 +911,6 @@ void pianoRoll::keyPressEvent( QKeyEvent * _ke )
}
break;
case Qt::Key_M:
if( _ke->modifiers() & Qt::ShiftModifier )
{
m_moveButton->setChecked( true );
}
else
{
_ke->ignore();
}
break;
case Qt::Key_Delete:
deleteSelectedNotes();
break;
@@ -1065,6 +1150,10 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
pattern::MelodyPattern );
// then set new note
// clear selection and select this new note
clearSelectedNotes();
// +32 to quanitize the note correctly when placing notes with
// the mouse. We do this here instead of in note.quantized
// because live notes should still be quantized at the half.
@@ -1072,7 +1161,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
midiTime note_len( newNoteLen() );
note new_note( note_len, note_pos, key_num );
new_note.setSelected( true );
note * created_new_note =
m_pattern->addNote( new_note );
@@ -1137,7 +1226,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
m_editMode == ModeErase )
{
// erase single note
m_mouseDownRight = true;
play_note = false;
if( it != notes.end() )
{
@@ -1170,15 +1259,6 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
// appears in wrong spot on mousedown
mouseMoveEvent( _me );
}
else if( _me->button() == Qt::RightButton &&
m_editMode == ModeSelect )
{
// when clicking right in select-move, we
// switch to move-mode
m_moveButton->setChecked( true );
play_note = false;
}
else if( _me->button() == Qt::LeftButton &&
m_editMode == ModeMove )
{
@@ -1189,6 +1269,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
m_moveStartKey = key_num;
m_action = ActionMoveSelection;
m_mouseDownLeft = true;
play_note = false;
engine::getSong()->setModified();
@@ -1312,6 +1393,19 @@ void pianoRoll::computeSelectedNotes(bool shift)
void pianoRoll::mouseReleaseEvent( QMouseEvent * _me )
{
bool mustRepaint = false;
if( _me->button() & Qt::LeftButton )
{
m_mouseDownLeft = false;
mustRepaint = true;
}
if( _me->button() & Qt::RightButton )
{
m_mouseDownRight = false;
mustRepaint = true;
}
if( _me->button() & Qt::LeftButton &&
m_editMode == ModeSelect &&
m_action == ActionSelectNotes )
@@ -1356,6 +1450,11 @@ void pianoRoll::mouseReleaseEvent( QMouseEvent * _me )
{
QApplication::restoreOverrideCursor();
}
if( mustRepaint )
{
repaint();
}
}
@@ -2373,7 +2472,21 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
// draw current edit-mode-icon below the cursor
switch( m_editMode )
{
case ModeDraw: cursor = s_toolDraw; break;
case ModeDraw:
if( m_mouseDownRight )
{
cursor = s_toolErase;
}
else if( m_action == ActionMoveSelection ||
m_action == ActionMoveNote )
{
cursor = s_toolMove;
}
else
{
cursor = s_toolDraw;
}
break;
case ModeErase: cursor = s_toolErase; break;
case ModeSelect: cursor = s_toolSelect; break;
case ModeMove: cursor = s_toolMove; break;