diff --git a/ChangeLog b/ChangeLog index 5052a4a90..098c98dea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-11-29 Andrew Kelley + + * 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 * include/resources_tree_view.h: diff --git a/TODO b/TODO index ee24588d1..91c39c181 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/include/piano_roll.h b/include/piano_roll.h index df6673d82..1743d63ef 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -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; diff --git a/src/core/note.cpp b/src/core/note.cpp index 732bda4de..3f821228c 100644 --- a/src/core/note.cpp +++ b/src/core/note.cpp @@ -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 ); } diff --git a/src/gui/piano_roll.cpp b/src/gui/piano_roll.cpp index 5cd9c07be..60c7823e4 100644 --- a/src/gui/piano_roll.cpp +++ b/src/gui/piano_roll.cpp @@ -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;