From 563a3bbc9cdc75bf6324b5a18367ec990d81f6fe Mon Sep 17 00:00:00 2001 From: akimaze <63190361+akimaze@users.noreply.github.com> Date: Thu, 30 Apr 2020 04:22:28 +0200 Subject: [PATCH] Piano roll vertical zoom (#5442) --- include/PianoRoll.h | 14 ++- src/gui/editors/PianoRoll.cpp | 226 +++++++++++++++++++++------------- 2 files changed, 156 insertions(+), 84 deletions(-) diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 27a15149e8a..8421392c36b 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -180,7 +180,7 @@ class PianoRoll : public QWidget void focusOutEvent( QFocusEvent * ) override; int getKey( int y ) const; - static void drawNoteRect( QPainter & p, int x, int y, + void drawNoteRect( QPainter & p, int x, int y, int width, const Note * n, const QColor & noteCol, const QColor & noteTextColor, const QColor & selCol, const int noteOpc, const bool borderless, bool drawNoteName ); void removeSelection(); @@ -192,6 +192,8 @@ class PianoRoll : public QWidget // for entering values with dblclick in the vol/pan bars void enterValue( NoteVector* nv ); + void updateYScroll(); + protected slots: void play(); void record(); @@ -217,6 +219,7 @@ protected slots: void updatePositionStepRecording(const MidiTime & t ); void zoomingChanged(); + void zoomingYChanged(); void quantizeChanged(); void noteLengthChanged(); void quantizeNotes(); @@ -330,12 +333,14 @@ protected slots: static TextFloat * s_textFloat; ComboBoxModel m_zoomingModel; + ComboBoxModel m_zoomingYModel; ComboBoxModel m_quantizeModel; ComboBoxModel m_noteLenModel; ComboBoxModel m_scaleModel; ComboBoxModel m_chordModel; static const QVector m_zoomLevels; + static const QVector m_zoomYLevels; Pattern* m_pattern; NoteVector m_ghostNotes; @@ -385,6 +390,12 @@ protected slots: int m_ppb; // pixels per bar int m_totalKeysToScroll; + int m_keyLineHeight; + int m_octaveHeight; + int m_whiteKeySmallHeight; + int m_whiteKeyBigHeight; + int m_blackKeyHeight; + // remember these values to use them // for the next note that is set MidiTime m_lenOfNewNotes; @@ -501,6 +512,7 @@ private slots: PianoRoll* m_editor; ComboBox * m_zoomingComboBox; + ComboBox * m_zoomingYComboBox; ComboBox * m_quantizeComboBox; ComboBox * m_noteLenComboBox; ComboBox * m_scaleComboBox; diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index d49c6f0b798..510fc800ea3 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -78,11 +78,11 @@ const int SCROLLBAR_SIZE = 12; const int PIANO_X = 0; const int WHITE_KEY_WIDTH = 64; -const int WHITE_KEY_SMALL_HEIGHT = 18; -const int WHITE_KEY_BIG_HEIGHT = 24; -const int BLACK_KEY_HEIGHT = 16; -const int KEY_LINE_HEIGHT = 12; -const int OCTAVE_HEIGHT = KEY_LINE_HEIGHT * KeysPerOctave; // = 12 * 12; +const int BLACK_KEY_WIDTH = 41; + +const int DEFAULT_KEY_LINE_HEIGHT = 12; +const int DEFAULT_CELL_WIDTH = 12; + const int NOTE_EDIT_RESIZE_BAR = 6; const int NOTE_EDIT_MIN_HEIGHT = 50; @@ -128,8 +128,6 @@ static QString getNoteString( int key ) return s_noteStrings[key % 12] + QString::number( static_cast( key / KeysPerOctave ) ); } - - // used for drawing of piano PianoRoll::PianoRollKeyTypes PianoRoll::prKeyOrder[] = { @@ -139,10 +137,13 @@ PianoRoll::PianoRollKeyTypes PianoRoll::prKeyOrder[] = } ; -const int DEFAULT_PR_PPB = KEY_LINE_HEIGHT * DefaultStepsPerBar; +const int DEFAULT_PR_PPB = DEFAULT_CELL_WIDTH * DefaultStepsPerBar; const QVector PianoRoll::m_zoomLevels = - { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f }; + {0.125f, 0.25f, 0.5f, 1.0f, 1.5f, 2.0f, 4.0f, 8.0f}; + +const QVector PianoRoll::m_zoomYLevels = + {0.25f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 4.0f}; PianoRoll::PianoRoll() : @@ -150,6 +151,7 @@ PianoRoll::PianoRoll() : m_noteEditMenu( NULL ), m_semiToneMarkerMenu( NULL ), m_zoomingModel(), + m_zoomingYModel(), m_quantizeModel(), m_noteLenModel(), m_scaleModel(), @@ -171,6 +173,11 @@ PianoRoll::PianoRoll() : m_oldNotesEditHeight( 100 ), m_notesEditHeight( 100 ), m_ppb( DEFAULT_PR_PPB ), + m_keyLineHeight(DEFAULT_KEY_LINE_HEIGHT), + m_octaveHeight(m_keyLineHeight * KeysPerOctave), + m_whiteKeySmallHeight(round(m_keyLineHeight * 1.5)), + m_whiteKeyBigHeight(m_keyLineHeight * 2), + m_blackKeyHeight(round(m_keyLineHeight * 1.3333)), m_lenOfNewNotes( MidiTime( 0, DefaultTicksPerBar/4 ) ), m_lastNoteVolume( DefaultVolume ), m_lastNotePanning( DefaultPanning ), @@ -352,6 +359,15 @@ PianoRoll::PianoRoll() : connect( &m_zoomingModel, SIGNAL( dataChanged() ), this, SLOT( zoomingChanged() ) ); + // zoom y + for (float const & zoomLevel : m_zoomYLevels) + { + m_zoomingYModel.addItem(QString( "%1\%" ).arg(zoomLevel * 100)); + } + m_zoomingYModel.setValue(m_zoomingYModel.findText("100%")); + connect(&m_zoomingYModel, SIGNAL(dataChanged()), + this, SLOT(zoomingYChanged())); + // Set up quantization model m_quantizeModel.addItem( tr( "Note lock" ) ); for( int i = 0; i <= NUM_EVEN_LENGTHS; ++i ) @@ -951,7 +967,7 @@ void PianoRoll::drawNoteRect( QPainter & p, int x, int y, const int borderWidth = borders ? 1 : 0; - const int noteHeight = KEY_LINE_HEIGHT - 1 - borderWidth; + const int noteHeight = m_keyLineHeight - 1 - borderWidth; int noteWidth = width + 1 - borderWidth; // adjust note to make it a bit faded if it has a lower volume @@ -993,7 +1009,12 @@ void PianoRoll::drawNoteRect( QPainter & p, int x, int y, int const distanceToBorder = 2; int const xOffset = borderWidth + distanceToBorder; - int const yOffset = (noteHeight + noteTextHeight) / 2; + + // noteTextHeight, textSize are not suitable for determining vertical spacing, + // capHeight() can be used for this, but requires Qt 5.8. + // We use boundingRect() with QChar (the QString version returns wrong value). + QRect const boundingRect = fontMetrics.boundingRect(QChar::fromLatin1('H')); + int const yOffset = (noteHeight - boundingRect.top() - boundingRect.bottom()) / 2; if (textSize.width() < noteWidth - xOffset) { @@ -1022,7 +1043,7 @@ void PianoRoll::drawNoteRect( QPainter & p, int x, int y, void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x, int _y ) const { - int middle_y = _y + KEY_LINE_HEIGHT / 2; + int middle_y = _y + m_keyLineHeight / 2; _p.setPen( noteColor() ); _p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN, width() - WHITE_KEY_WIDTH, @@ -1039,7 +1060,7 @@ void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x, const float level = it.value(); - int pos_y = middle_y - level * KEY_LINE_HEIGHT; + int pos_y = middle_y - level * m_keyLineHeight; if( old_x != 0 && old_y != 0 ) { @@ -2596,7 +2617,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) int visible_keys = ( height() - PR_TOP_MARGIN - PR_BOTTOM_MARGIN - m_notesEditHeight ) / - KEY_LINE_HEIGHT + 2; + m_keyLineHeight + 2; const int s_key = m_startKey - 1; if( key_num <= s_key ) @@ -2846,6 +2867,11 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // set font-size to 8 p.setFont( pointSize<8>( p.font() ) ); + QFontMetrics fontMetrics(p.font()); + QRect const boundingRect = fontMetrics.boundingRect(QChar::fromLatin1('H')); + // This is two times of the y coordinate of the center of the bounding rectangle + // (-(top+bottom)=-2(center)) but labelHeight is more intuitive/describing name + int const labelHeight = - boundingRect.top() - boundingRect.bottom(); // y_offset is used to align the piano-keys on the key-lines int y_offset = 0; @@ -2853,20 +2879,20 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // calculate y_offset according to first key switch( prKeyOrder[m_startKey % KeysPerOctave] ) { - case PR_BLACK_KEY: y_offset = KEY_LINE_HEIGHT / 4; break; - case PR_WHITE_KEY_BIG: y_offset = KEY_LINE_HEIGHT / 2; break; + case PR_BLACK_KEY: y_offset = m_keyLineHeight / 4; break; + case PR_WHITE_KEY_BIG: y_offset = m_keyLineHeight / 2; break; case PR_WHITE_KEY_SMALL: if( prKeyOrder[( ( m_startKey + 1 ) % KeysPerOctave)] != PR_BLACK_KEY ) { - y_offset = KEY_LINE_HEIGHT / 2; + y_offset = m_keyLineHeight / 2; } break; } // start drawing at the bottom int key_line_y = keyAreaBottom() - 1; // used for aligning black-keys later - int first_white_key_height = WHITE_KEY_SMALL_HEIGHT; + int first_white_key_height = m_whiteKeySmallHeight; // key-counter - only needed for finding out whether the processed // key is the first one int keys_processed = 0; @@ -2875,7 +2901,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // draw all white keys... for( int y = key_line_y + 1 + y_offset; y > PR_TOP_MARGIN; - key_line_y -= KEY_LINE_HEIGHT, ++keys_processed ) + key_line_y -= m_keyLineHeight, ++keys_processed ) { // check for white key that is only half visible on the // bottom of piano-roll @@ -2884,16 +2910,16 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) PR_BLACK_KEY ) { // draw it! - p.drawPixmap( PIANO_X, y - WHITE_KEY_SMALL_HEIGHT, + p.drawPixmap( PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, *s_whiteKeySmallPm ); // update y-pos - y -= WHITE_KEY_SMALL_HEIGHT / 2; + y -= m_whiteKeySmallHeight / 2; // move first black key down (we didn't draw whole // white key so black key needs to be lifted down) // (default for first_white_key_height = - // WHITE_KEY_SMALL_HEIGHT, so WHITE_KEY_SMALL_HEIGHT/2 + // m_whiteKeySmallHeight, so m_whiteKeySmallHeight/2 // is smaller) - first_white_key_height = WHITE_KEY_SMALL_HEIGHT / 2; + first_white_key_height = m_whiteKeySmallHeight / 2; } // check whether to draw a big or a small white key if( prKeyOrder[key % KeysPerOctave] == PR_WHITE_KEY_SMALL ) @@ -2901,14 +2927,16 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // draw a small one while checking if it is pressed or not if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) { - p.drawPixmap( PIANO_X, y - WHITE_KEY_SMALL_HEIGHT, *s_whiteKeySmallPressedPm ); + p.drawPixmap(PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, + *s_whiteKeySmallPressedPm); } else { - p.drawPixmap( PIANO_X, y - WHITE_KEY_SMALL_HEIGHT, *s_whiteKeySmallPm ); + p.drawPixmap(PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, + *s_whiteKeySmallPm); } // update y-pos - y -= WHITE_KEY_SMALL_HEIGHT; + y -= m_whiteKeySmallHeight; } else if( prKeyOrder[key % KeysPerOctave] == PR_WHITE_KEY_BIG ) @@ -2916,47 +2944,51 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // draw a big one while checking if it is pressed or not if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) { - p.drawPixmap( PIANO_X, y - WHITE_KEY_BIG_HEIGHT, *s_whiteKeyBigPressedPm ); + p.drawPixmap(PIANO_X, y - m_whiteKeyBigHeight, WHITE_KEY_WIDTH, m_whiteKeyBigHeight, + *s_whiteKeyBigPressedPm); } else { - p.drawPixmap( PIANO_X, y-WHITE_KEY_BIG_HEIGHT, *s_whiteKeyBigPm ); + p.drawPixmap(PIANO_X, y-m_whiteKeyBigHeight, WHITE_KEY_WIDTH, m_whiteKeyBigHeight, + *s_whiteKeyBigPm); } // if a big white key has been the first key, // black keys needs to be lifted up if( keys_processed == 0 ) { - first_white_key_height = WHITE_KEY_BIG_HEIGHT; + first_white_key_height = m_whiteKeyBigHeight; } // update y-pos - y -= WHITE_KEY_BIG_HEIGHT; + y -= m_whiteKeyBigHeight; } // Compute the corrections for the note names int yCorrectionForNoteLabels = 0; int keyCode = key % KeysPerOctave; - switch( keyCode ) + switch (keyCode) { - case 0: - case 5: - yCorrectionForNoteLabels = -4; + case 0: // C + case 5: // F + yCorrectionForNoteLabels = (m_whiteKeySmallHeight - labelHeight + 1) / -2; break; - case 2: - case 7: - case 9: - yCorrectionForNoteLabels = -2; + case 2: // D + case 7: // G + case 9: // A + yCorrectionForNoteLabels = (m_whiteKeyBigHeight / 2 - labelHeight + 1) / -2; break; - case 4: - case 11: - yCorrectionForNoteLabels = 2; + case 4: // E + case 11: // B + // calculate center point of key and move half of text + yCorrectionForNoteLabels = -(((m_whiteKeySmallHeight - (m_whiteKeySmallHeight * 2 + 3) / 6) / 4) + - labelHeight / 2); break; } if( Piano::isWhiteKey( key ) ) { // Draw note names if activated in the preferences, C notes are always drawn - if ( key % 12 == 0 || drawNoteNames ) + if ( (key % 12 == 0 || drawNoteNames) && m_keyLineHeight > 10 ) { QString noteString = getNoteString( key ); @@ -3000,14 +3032,14 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) PR_BLACK_KEY ) { // draw the black key! - p.drawPixmap( PIANO_X, y - BLACK_KEY_HEIGHT / 2, + p.drawPixmap( PIANO_X, y - m_blackKeyHeight / 2, BLACK_KEY_WIDTH, m_blackKeyHeight, *s_blackKeyPm ); // is the one after the start-note a black key?? if( prKeyOrder[( key + 1 ) % KeysPerOctave] != PR_BLACK_KEY ) { // no, then move it up! - y -= KEY_LINE_HEIGHT / 2; + y -= m_keyLineHeight / 2; } } // current key black? @@ -3019,19 +3051,19 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) { p.drawPixmap( PIANO_X, y - ( first_white_key_height - - WHITE_KEY_SMALL_HEIGHT ) - - WHITE_KEY_SMALL_HEIGHT/2 - 1 - - BLACK_KEY_HEIGHT, *s_blackKeyPressedPm ); + m_whiteKeySmallHeight ) - + m_whiteKeySmallHeight/2 - 1 - + m_blackKeyHeight, BLACK_KEY_WIDTH, m_blackKeyHeight, *s_blackKeyPressedPm ); } else { p.drawPixmap( PIANO_X, y - ( first_white_key_height - - WHITE_KEY_SMALL_HEIGHT ) - - WHITE_KEY_SMALL_HEIGHT/2 - 1 - - BLACK_KEY_HEIGHT, *s_blackKeyPm ); + m_whiteKeySmallHeight ) - + m_whiteKeySmallHeight/2 - 1 - + m_blackKeyHeight, BLACK_KEY_WIDTH, m_blackKeyHeight, *s_blackKeyPm ); } // update y-pos - y -= WHITE_KEY_BIG_HEIGHT; + y -= m_whiteKeyBigHeight; // reset white-counter white_cnt = 0; } @@ -3042,7 +3074,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) ++white_cnt; if( white_cnt > 1 ) { - y -= WHITE_KEY_BIG_HEIGHT/2; + y -= m_whiteKeyBigHeight/2; } } @@ -3103,7 +3135,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // Draw horizontal lines key = m_startKey; for( int y = keyAreaBottom() - 1; y > PR_TOP_MARGIN; - y -= KEY_LINE_HEIGHT ) + y -= m_keyLineHeight ) { if( static_cast( key % KeysPerOctave ) == Key_C ) { @@ -3162,14 +3194,14 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) { const int key_num = m_markedSemiTones.at( i ); const int y = keyAreaBottom() + 5 - - KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 ); + - m_keyLineHeight * ( key_num - m_startKey + 1 ); if( y > keyAreaBottom() ) { break; } - p.fillRect( WHITE_KEY_WIDTH + 1, y - KEY_LINE_HEIGHT / 2, width() - 10, KEY_LINE_HEIGHT + 1, + p.fillRect( WHITE_KEY_WIDTH + 1, y - m_keyLineHeight / 2, width() - 10, m_keyLineHeight + 1, markedSemitoneColor() ); } } @@ -3200,7 +3232,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) height() - PR_TOP_MARGIN ); const int visible_keys = ( keyAreaBottom()-keyAreaTop() ) / - KEY_LINE_HEIGHT + 2; + m_keyLineHeight + 2; QPolygonF editHandles; @@ -3239,7 +3271,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // we've done and checked all, let's draw the // note drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * KEY_LINE_HEIGHT, + y_base - key * m_keyLineHeight, note_width, note, ghostNoteColor(), ghostNoteTextColor(), selectedNoteColor(), ghostNoteOpacity(), ghostNoteBorders(), drawNoteNames ); } @@ -3281,7 +3313,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // we've done and checked all, let's draw the // note drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * KEY_LINE_HEIGHT, + y_base - key * m_keyLineHeight, note_width, note, noteColor(), noteTextColor(), selectedNoteColor(), noteOpacity(), noteBorders(), drawNoteNames ); } @@ -3332,7 +3364,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) { drawDetuningInfo( p, note, x + WHITE_KEY_WIDTH, - y_base - key * KEY_LINE_HEIGHT ); + y_base - key * m_keyLineHeight ); p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN, width() - WHITE_KEY_WIDTH, height() - PR_TOP_MARGIN); @@ -3368,7 +3400,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // we've done and checked all, let's draw the note drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * KEY_LINE_HEIGHT, + y_base - key * m_keyLineHeight, note_width, note, m_stepRecorder.curStepNoteColor(), noteTextColor(), selectedNoteColor(), noteOpacity(), noteBorders(), drawNoteNames ); } @@ -3399,8 +3431,8 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) MidiTime::ticksPerBar(); int w = ( ( ( sel_pos_end - m_currentPosition ) * m_ppb ) / MidiTime::ticksPerBar() ) - x; - int y = (int) y_base - sel_key_start * KEY_LINE_HEIGHT; - int h = (int) y_base - sel_key_end * KEY_LINE_HEIGHT - y; + int y = (int) y_base - sel_key_start * m_keyLineHeight; + int h = (int) y_base - sel_key_end * m_keyLineHeight - y; p.setPen( selectedNoteColor() ); p.setBrush( Qt::NoBrush ); p.drawRect( x + WHITE_KEY_WIDTH, y, w, h ); @@ -3426,8 +3458,8 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) if( hasValidPattern() ) { int key_num = getKey( mapFromGlobal( QCursor::pos() ).y() ); - p.fillRect( 10, keyAreaBottom() + 3 - KEY_LINE_HEIGHT * - ( key_num - m_startKey + 1 ), width() - 10, KEY_LINE_HEIGHT - 7, currentKeyCol ); + p.fillRect( 10, keyAreaBottom() + 3 - m_keyLineHeight * + ( key_num - m_startKey + 1 ), width() - 10, m_keyLineHeight - 7, currentKeyCol ); } // bar to resize note edit area @@ -3475,23 +3507,7 @@ void PianoRoll::resizeEvent(QResizeEvent * re) SCROLLBAR_SIZE, width()-WHITE_KEY_WIDTH, SCROLLBAR_SIZE ); - m_topBottomScroll->setGeometry( width() - SCROLLBAR_SIZE, PR_TOP_MARGIN, - SCROLLBAR_SIZE, - height() - PR_TOP_MARGIN - - SCROLLBAR_SIZE ); - - int total_pixels = OCTAVE_HEIGHT * NumOctaves - ( height() - - PR_TOP_MARGIN - PR_BOTTOM_MARGIN - - m_notesEditHeight ); - m_totalKeysToScroll = total_pixels * KeysPerOctave / OCTAVE_HEIGHT; - - m_topBottomScroll->setRange( 0, m_totalKeysToScroll ); - - if( m_startKey > m_totalKeysToScroll ) - { - m_startKey = m_totalKeysToScroll; - } - m_topBottomScroll->setValue( m_totalKeysToScroll - m_startKey ); + updateYScroll(); Engine::getSong()->getPlayPos( Song::Mode_PlayPattern ).m_timeLine->setFixedWidth( width() ); @@ -3664,7 +3680,7 @@ int PianoRoll::getKey(int y ) const { int key_line_y = keyAreaBottom() - 1; // pressed key on piano - int key_num = ( key_line_y - y ) / KEY_LINE_HEIGHT; + int key_num = ( key_line_y - y ) / m_keyLineHeight; key_num += m_startKey; // some range-checking-stuff @@ -4039,6 +4055,28 @@ void PianoRoll::enterValue( NoteVector* nv ) } +void PianoRoll::updateYScroll() +{ + m_topBottomScroll->setGeometry(width() - SCROLLBAR_SIZE, PR_TOP_MARGIN, + SCROLLBAR_SIZE, + height() - PR_TOP_MARGIN - + SCROLLBAR_SIZE); + + int total_pixels = m_octaveHeight * NumOctaves - (height() - + PR_TOP_MARGIN - PR_BOTTOM_MARGIN - + m_notesEditHeight); + m_totalKeysToScroll = total_pixels * KeysPerOctave / m_octaveHeight; + + m_topBottomScroll->setRange(0, m_totalKeysToScroll); + + if(m_startKey > m_totalKeysToScroll) + { + m_startKey = m_totalKeysToScroll; + } + m_topBottomScroll->setValue(m_totalKeysToScroll - m_startKey); +} + + void PianoRoll::copyToClipboard( const NoteVector & notes ) const { DataFile dataFile( DataFile::ClipboardData ); @@ -4279,6 +4317,17 @@ void PianoRoll::zoomingChanged() } +void PianoRoll::zoomingYChanged() +{ + m_keyLineHeight = m_zoomYLevels[m_zoomingYModel.value()] * DEFAULT_KEY_LINE_HEIGHT; + m_octaveHeight = m_keyLineHeight * KeysPerOctave; + m_whiteKeySmallHeight = round(m_keyLineHeight * 1.5); + m_whiteKeyBigHeight = m_keyLineHeight * 2; + m_blackKeyHeight = round(m_keyLineHeight * 1.3333); + + updateYScroll(); + update(); +} void PianoRoll::quantizeChanged() @@ -4501,13 +4550,21 @@ PianoRollWindow::PianoRollWindow() : DropToolBar *zoomAndNotesToolBar = addDropToolBarToTop( tr( "Zoom and note controls" ) ); QLabel * zoom_lbl = new QLabel( m_toolBar ); - zoom_lbl->setPixmap( embed::getIconPixmap( "zoom" ) ); + zoom_lbl->setPixmap( embed::getIconPixmap( "zoom_x" ) ); m_zoomingComboBox = new ComboBox( m_toolBar ); m_zoomingComboBox->setModel( &m_editor->m_zoomingModel ); m_zoomingComboBox->setFixedSize( 64, 22 ); m_zoomingComboBox->setToolTip( tr( "Horizontal zooming") ); + QLabel * zoom_y_lbl = new QLabel(m_toolBar); + zoom_y_lbl->setPixmap(embed::getIconPixmap("zoom_y")); + + m_zoomingYComboBox = new ComboBox(m_toolBar); + m_zoomingYComboBox->setModel(&m_editor->m_zoomingYModel); + m_zoomingYComboBox->setFixedSize(64, 22); + m_zoomingYComboBox->setToolTip(tr("Vertical zooming")); + // setup quantize-stuff QLabel * quantize_lbl = new QLabel( m_toolBar ); quantize_lbl->setPixmap( embed::getIconPixmap( "quantize" ) ); @@ -4555,6 +4612,9 @@ PianoRollWindow::PianoRollWindow() : zoomAndNotesToolBar->addWidget( zoom_lbl ); zoomAndNotesToolBar->addWidget( m_zoomingComboBox ); + zoomAndNotesToolBar->addWidget(zoom_y_lbl); + zoomAndNotesToolBar->addWidget(m_zoomingYComboBox); + zoomAndNotesToolBar->addSeparator(); zoomAndNotesToolBar->addWidget( quantize_lbl ); zoomAndNotesToolBar->addWidget( m_quantizeComboBox );