diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 60b894f1fbc..520416be80d 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -240,6 +240,7 @@ protected slots: EditModes m_editMode; + bool m_mouseDownLeft; bool m_mouseDownRight; //true if right click is being held down TimeLineWidget * m_timeLine; diff --git a/include/FadeButton.h b/include/FadeButton.h index 57d8ba1e693..54703d19476 100644 --- a/include/FadeButton.h +++ b/include/FadeButton.h @@ -46,6 +46,7 @@ class FadeButton : public QAbstractButton public slots: void activate(); + void activateOnce(); void noteEnd(); diff --git a/include/FileBrowser.h b/include/FileBrowser.h index b84ba5e5403..d36eacf0775 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -127,6 +127,7 @@ private slots: void openInNewInstrumentTrackSE( void ); void sendToActiveInstrumentTrack( void ); void updateDirectory( QTreeWidgetItem * item ); + void openContainingFolder(); } ; diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index d72331e5284..f2602686b59 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -333,7 +333,6 @@ private slots: void midiInSelected(); void midiOutSelected(); void midiConfigChanged(); - void muteChanged(); void assignFxLine( int channelIndex ); void createFxLine(); @@ -357,6 +356,10 @@ private slots: QPoint m_lastPos; + FadeButton * getActivityIndicator() + { + return m_activityIndicator; + } friend class InstrumentTrackWindow; 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/include/SampleTrack.h b/include/SampleTrack.h index 2bad4d91042..47cc0df3945 100644 --- a/include/SampleTrack.h +++ b/include/SampleTrack.h @@ -29,6 +29,7 @@ #include #include "AudioPort.h" +#include "FadeButton.h" #include "FxMixer.h" #include "FxLineLcdSpinBox.h" #include "Track.h" @@ -161,6 +162,20 @@ class SampleTrack : public Track return "sampletrack"; } + bool isPlaying() + { + return m_isPlaying; + } + + void setPlaying(bool playing) + { + if (m_isPlaying != playing) { emit playingChanged(); } + m_isPlaying = playing; + } + +signals: + void playingChanged(); + public slots: void updateTcos(); void setPlayingTcos( bool isPlaying ); @@ -171,6 +186,7 @@ public slots: FloatModel m_panningModel; IntModel m_effectChannelModel; AudioPort m_audioPort; + bool m_isPlaying; @@ -209,6 +225,7 @@ class SampleTrackView : public TrackView public slots: void showEffects(); + void updateIndicator(); protected: @@ -230,9 +247,14 @@ private slots: SampleTrackWindow * m_window; Knob * m_volumeKnob; Knob * m_panningKnob; + FadeButton * m_activityIndicator; TrackLabelButton * m_tlb; + FadeButton * getActivityIndicator() + { + return m_activityIndicator; + } friend class SampleTrackWindow; diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 9f9ae1b3f82..80a22d69c35 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -74,6 +74,7 @@ private slots: void toggleNoteLabels(bool enabled); void toggleCompactTrackButtons(bool enabled); void toggleOneInstrumentTrackWindow(bool enabled); + void toggleSideBarOnRight(bool enabled); void toggleMMPZ(bool enabled); void toggleDisableBackup(bool enabled); void toggleOpenLastProject(bool enabled); @@ -130,6 +131,7 @@ private slots: bool m_printNoteLabels; bool m_compactTrackButtons; bool m_oneInstrumentTrackWindow; + bool m_sideBarOnRight; bool m_MMPZ; bool m_disableBackup; bool m_openLastProject; diff --git a/include/Track.h b/include/Track.h index de622d0fb64..07cee8ffd6b 100644 --- a/include/Track.h +++ b/include/Track.h @@ -39,6 +39,7 @@ #include "AutomatableModel.h" #include "ModelView.h" #include "DataFile.h" +#include "FadeButton.h" class QMenu; @@ -739,12 +740,19 @@ public slots: Actions m_action; + virtual FadeButton * getActivityIndicator() + { + return nullptr; + } + + void setIndicatorMute(FadeButton* indicator, bool muted); friend class TrackLabelButton; private slots: void createTCOView( TrackContentObject * tco ); + void muteChanged(); } ; diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index b38c704ef02..2fd1cea125f 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -178,9 +178,16 @@ const AutomationPattern::objectVector& AutomationPattern::objects() const MidiTime AutomationPattern::timeMapLength() const { - if( m_timeMap.isEmpty() ) return 0; + MidiTime one_bar = MidiTime(1, 0); + if (m_timeMap.isEmpty()) { return one_bar; } + timeMap::const_iterator it = m_timeMap.end(); - return MidiTime( MidiTime( (it-1).key() ).nextFullBar(), 0 ); + tick_t last_tick = static_cast((it-1).key()); + // if last_tick is 0 (single item at tick 0) + // return length as a whole bar to prevent disappearing TCO + if (last_tick == 0) { return one_bar; } + + return MidiTime(last_tick); } @@ -188,7 +195,8 @@ MidiTime AutomationPattern::timeMapLength() const void AutomationPattern::updateLength() { - changeLength( timeMapLength() ); + // Do not resize down in case user manually extended up + changeLength(qMax(length(), timeMapLength())); } @@ -223,12 +231,7 @@ MidiTime AutomationPattern::putValue( const MidiTime & time, } generateTangents( it, 3 ); - // we need to maximize our length in case we're part of a hidden - // automation track as the user can't resize this pattern - if( getTrack() && getTrack()->type() == Track::HiddenAutomationTrack ) - { - updateLength(); - } + updateLength(); emit dataChanged(); @@ -251,10 +254,7 @@ void AutomationPattern::removeValue( const MidiTime & time ) } generateTangents(it, 3); - if( getTrack() && getTrack()->type() == Track::HiddenAutomationTrack ) - { - updateLength(); - } + updateLength(); emit dataChanged(); } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index cb430da964c..f6b10928013 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -159,7 +159,7 @@ void TrackContentObject::movePosition( const MidiTime & pos ) /*! \brief Change the length of this TrackContentObject * - * If the track content object's length has chaanged, update it. We + * If the track content object's length has changed, update it. We * also add a journal entry for undo and update the display. * * \param _length The new length of the track content object. @@ -2719,6 +2719,9 @@ TrackView::TrackView( Track * track, TrackContainerView * tcv ) : connect( &m_track->m_mutedModel, SIGNAL( dataChanged() ), &m_trackContentWidget, SLOT( update() ) ); + connect(&m_track->m_mutedModel, SIGNAL(dataChanged()), + this, SLOT(muteChanged())); + connect( &m_track->m_soloModel, SIGNAL( dataChanged() ), m_track, SLOT( toggleSolo() ), Qt::DirectConnection ); // create views for already existing TCOs @@ -3051,3 +3054,21 @@ void TrackView::createTCOView( TrackContentObject * tco ) } tco->selectViewOnCreate( false ); } + + + + +void TrackView::muteChanged() +{ + FadeButton * indicator = getActivityIndicator(); + if (indicator) { setIndicatorMute(indicator, m_track->m_mutedModel.value()); } +} + + + + +void TrackView::setIndicatorMute(FadeButton* indicator, bool muted) +{ + QPalette::ColorRole role = muted ? QPalette::Highlight : QPalette::BrightText; + indicator->setActiveColor(QApplication::palette().color(QPalette::Active, role)); +} diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index 809518683a5..c976c39f689 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -24,6 +24,7 @@ */ +#include #include #include #include @@ -363,25 +364,41 @@ QList FileBrowserTreeWidget::expandedDirs( QTreeWidgetItem * item ) con void FileBrowserTreeWidget::contextMenuEvent(QContextMenuEvent * e ) { - FileItem * f = dynamic_cast( itemAt( e->pos() ) ); - if( f != NULL && ( f->handling() == FileItem::LoadAsPreset || - f->handling() == FileItem::LoadByPlugin ) ) + FileItem * f = dynamic_cast(itemAt(e->pos())); + if (f == nullptr) { + return; + } + + if (f->handling() == FileItem::LoadAsPreset || f->handling() == FileItem::LoadByPlugin) + { + // Set the member to the current FileItem so that it is available during the + // execution of the slots of the context menu we are about to create and execute. m_contextMenuItem = f; - QMenu contextMenu( this ); - contextMenu.addAction( tr( "Send to active instrument-track" ), - this, - SLOT( sendToActiveInstrumentTrack() ) ); - contextMenu.addAction( tr( "Open in new instrument-track/" - "Song Editor" ), - this, - SLOT( openInNewInstrumentTrackSE() ) ); - contextMenu.addAction( tr( "Open in new instrument-track/" - "B+B Editor" ), - this, - SLOT( openInNewInstrumentTrackBBE() ) ); - contextMenu.exec( e->globalPos() ); - m_contextMenuItem = NULL; + + QMenu contextMenu(this); + + contextMenu.addAction(tr("Send to active instrument-track"), + this, + SLOT(sendToActiveInstrumentTrack())); + contextMenu.addAction(tr("Open in new instrument-track/Song Editor"), + this, + SLOT(openInNewInstrumentTrackSE())); + contextMenu.addAction(tr("Open in new instrument-track/B+B Editor"), + this, + SLOT(openInNewInstrumentTrackBBE())); + + contextMenu.addSeparator(); + + contextMenu.addAction(QIcon(embed::getIconPixmap("folder")), + tr("Open containing folder"), + this, + SLOT(openContainingFolder())); + + contextMenu.exec(e->globalPos()); + + // The context menu has been executed so we can reset this member back to nullptr. + m_contextMenuItem = nullptr; } } @@ -671,6 +688,22 @@ void FileBrowserTreeWidget::openInNewInstrumentTrackSE( void ) +void FileBrowserTreeWidget::openContainingFolder() +{ + if (m_contextMenuItem) + { + // Delegate to QDesktopServices::openUrl with the directory of the selected file. Please note that + // this will only open the directory but not select the file as this is much more complicated due + // to different implementations that are needed for different platforms (Linux/Windows/MacOS). + + // Using QDesktopServices::openUrl seems to be the most simple cross platform way which uses + // functionality that's already available in Qt. + QFileInfo fileInfo(m_contextMenuItem->fullName()); + QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.dir().path())); + } +} + + void FileBrowserTreeWidget::sendToActiveInstrumentTrack( void ) { diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 3eb532981d0..bf8863ec616 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -117,6 +117,7 @@ MainWindow::MainWindow() : splitter->setChildrenCollapsible( false ); ConfigManager* confMgr = ConfigManager::inst(); + bool sideBarOnRight = confMgr->value("ui", "sidebaronright").toInt(); emit initProgress(tr("Preparing plugin browser")); sideBar->appendTab( new PluginBrowser( splitter ) ); @@ -171,7 +172,7 @@ MainWindow::MainWindow() : embed::getIconPixmap( "computer" ).transformed( QTransform().rotate( 90 ) ), splitter, dirs_as_items) ); - m_workspace = new QMdiArea( splitter ); + m_workspace = new QMdiArea(splitter); // Load background emit initProgress(tr("Loading background picture")); @@ -194,9 +195,15 @@ MainWindow::MainWindow() : m_workspace->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); m_workspace->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); - hbox->addWidget( sideBar ); - hbox->addWidget( splitter ); - + hbox->addWidget(sideBar); + hbox->addWidget(splitter); + // If the user wants the sidebar on the right, we move the workspace and + // the splitter to the "left" side, or the first widgets in their list + if (sideBarOnRight) + { + splitter->insertWidget(0, m_workspace); + hbox->insertWidget(0, splitter); + } // create global-toolbar at the top of our window m_toolBar = new QWidget( main_widget ); diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index 885f43dec31..6de547b5ae2 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -100,6 +100,8 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : "ui", "compacttrackbuttons").toInt()), m_oneInstrumentTrackWindow(ConfigManager::inst()->value( "ui", "oneinstrumenttrackwindow").toInt()), + m_sideBarOnRight(ConfigManager::inst()->value( + "ui", "sidebaronright").toInt()), m_MMPZ(!ConfigManager::inst()->value( "app", "nommpz").toInt()), m_disableBackup(!ConfigManager::inst()->value( @@ -229,6 +231,8 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : m_compactTrackButtons, SLOT(toggleCompactTrackButtons(bool)), true); addLedCheckBox("Enable one instrument-track-window mode", gui_tw, counter, m_oneInstrumentTrackWindow, SLOT(toggleOneInstrumentTrackWindow(bool)), true); + addLedCheckBox("Show sidebar on the right-hand side", gui_tw, counter, + m_sideBarOnRight, SLOT(toggleSideBarOnRight(bool)), true); gui_tw->setFixedHeight(YDelta + YDelta * counter); @@ -876,6 +880,8 @@ void SetupDialog::accept() QString::number(m_compactTrackButtons)); ConfigManager::inst()->setValue("ui", "oneinstrumenttrackwindow", QString::number(m_oneInstrumentTrackWindow)); + ConfigManager::inst()->setValue("ui", "sidebaronright", + QString::number(m_sideBarOnRight)); ConfigManager::inst()->setValue("app", "nommpz", QString::number(!m_MMPZ)); ConfigManager::inst()->setValue("app", "disablebackup", @@ -980,6 +986,12 @@ void SetupDialog::toggleOneInstrumentTrackWindow(bool enabled) } +void SetupDialog::toggleSideBarOnRight(bool enabled) +{ + m_sideBarOnRight = enabled; +} + + void SetupDialog::toggleMMPZ(bool enabled) { m_MMPZ = enabled; diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index bf56e303981..048123ef5f8 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -96,6 +96,7 @@ AutomationEditor::AutomationEditor() : m_y_delta( DEFAULT_Y_DELTA ), m_y_auto( true ), m_editMode( DRAW ), + m_mouseDownLeft(false), m_mouseDownRight( false ), m_scrollBack( false ), m_barLineColor( 0, 0, 0 ), @@ -539,6 +540,10 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) ++it; } + if (mouseEvent->button() == Qt::LeftButton) + { + m_mouseDownLeft = true; + } if( mouseEvent->button() == Qt::RightButton ) { m_mouseDownRight = true; @@ -555,6 +560,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) drawLine( m_drawLastTick, m_drawLastLevel, pos_ticks, level ); + m_mouseDownLeft = false; } m_drawLastTick = pos_ticks; m_drawLastLevel = level; @@ -657,6 +663,11 @@ void AutomationEditor::mouseReleaseEvent(QMouseEvent * mouseEvent ) { bool mustRepaint = false; + if (mouseEvent->button() == Qt::LeftButton) + { + m_mouseDownLeft = false; + mustRepaint = true; + } if ( mouseEvent->button() == Qt::RightButton ) { m_mouseDownRight = false; @@ -742,7 +753,8 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; - if( mouseEvent->buttons() & Qt::LeftButton && m_editMode == DRAW ) + // m_mouseDownLeft used to prevent drag when drawing line + if (m_mouseDownLeft && m_editMode == DRAW) { if( m_action == MOVE_VALUE ) { diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index d49c6f0b798..0eb5df16343 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 ) { @@ -1391,7 +1412,7 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke) { m_ctrlMode = m_editMode; m_editMode = ModeSelect; - QApplication::changeOverrideCursor( Qt::ArrowCursor ); + setCursor( Qt::ArrowCursor ); ke->accept(); } break; @@ -1445,11 +1466,6 @@ void PianoRoll::keyReleaseEvent(QKeyEvent* ke ) void PianoRoll::leaveEvent(QEvent * e ) { - while( QApplication::overrideCursor() != NULL ) - { - QApplication::restoreOverrideCursor(); - } - QWidget::leaveEvent( e ); s_textFloat->hide(); update(); // cleaning inner mouse-related graphics @@ -1539,7 +1555,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) { m_ctrlMode = m_editMode; m_editMode = ModeSelect; - QApplication::changeOverrideCursor( QCursor( Qt::ArrowCursor ) ); + setCursor( Qt::ArrowCursor ); update(); } @@ -1757,8 +1773,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) m_action = ActionResizeNote; // set resize-cursor - QCursor c( Qt::SizeHorCursor ); - QApplication::setOverrideCursor( c ); + setCursor( Qt::SizeHorCursor ); } else { @@ -1771,8 +1786,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) m_action = ActionMoveNote; // set move-cursor - QCursor c( Qt::SizeAllCursor ); - QApplication::setOverrideCursor( c ); + setCursor( Qt::SizeAllCursor ); // if they're holding shift, copy all selected notes if( ! is_new_note && me->modifiers() & Qt::ShiftModifier ) @@ -2204,7 +2218,7 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me ) if( m_editMode == ModeDraw ) { - QApplication::restoreOverrideCursor(); + setCursor( Qt::ArrowCursor ); } if( mustRepaint ) @@ -2228,8 +2242,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) { if( me->y() > keyAreaBottom() && me->y() < noteEditTop() ) { - QApplication::setOverrideCursor( - QCursor( Qt::SizeVerCursor ) ); + setCursor( Qt::SizeVerCursor ); return; } } @@ -2442,37 +2455,19 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) bool atTail = note->length() > 0 && x > noteRightX - RESIZE_AREA_WIDTH; Qt::CursorShape cursorShape = atTail ? Qt::SizeHorCursor : - Qt::SizeAllCursor; - if( QApplication::overrideCursor() ) - { - if( QApplication::overrideCursor()->shape() != cursorShape ) - { - while( QApplication::overrideCursor() != NULL ) - { - QApplication::restoreOverrideCursor(); - } - QApplication::setOverrideCursor(QCursor(cursorShape)); - } - } - else - { - QApplication::setOverrideCursor(QCursor(cursorShape)); - } + Qt::SizeAllCursor; + setCursor( cursorShape ); } else { // the cursor is over no note, so restore cursor - while( QApplication::overrideCursor() != NULL ) - { - QApplication::restoreOverrideCursor(); - } + setCursor( Qt::ArrowCursor ); } } else if( me->buttons() & Qt::LeftButton && m_editMode == ModeSelect && m_action == ActionSelectNotes ) { - // change size of selection // get tick in which the cursor is posated @@ -2544,6 +2539,12 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) } } } + else if (me->buttons() == Qt::NoButton && m_editMode != ModeDraw) + { + // Is needed to restore cursor when it previously was set to + // Qt::SizeVerCursor (between keyAreaBottom and noteEditTop) + setCursor( Qt::ArrowCursor ); + } } else { @@ -2596,7 +2597,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 ) @@ -2622,7 +2623,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) --m_selectedKeys; } } - QApplication::restoreOverrideCursor(); + setCursor( Qt::ArrowCursor ); } m_lastMouseX = me->x(); @@ -2846,6 +2847,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 +2859,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 +2881,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 +2890,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 +2907,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 +2924,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 +3012,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 +3031,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 +3054,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) ++white_cnt; if( white_cnt > 1 ) { - y -= WHITE_KEY_BIG_HEIGHT/2; + y -= m_whiteKeyBigHeight/2; } } @@ -3103,7 +3115,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 +3174,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 +3212,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 +3251,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 +3293,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 +3344,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 +3380,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 +3411,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 +3438,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 +3487,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 +3660,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 +4035,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 +4297,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 +4530,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 +4592,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 ); diff --git a/src/gui/widgets/FadeButton.cpp b/src/gui/widgets/FadeButton.cpp index 8f75ea33be0..43f8061441a 100644 --- a/src/gui/widgets/FadeButton.cpp +++ b/src/gui/widgets/FadeButton.cpp @@ -2,7 +2,7 @@ * FadeButton.cpp - implementation of fade-button * * Copyright (c) 2005-2009 Tobias Doerffel - * + * * This file is part of LMMS - https://lmms.io * * This program is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ * Boston, MA 02110-1301 USA. * */ - + #include #include @@ -75,6 +75,14 @@ void FadeButton::activate() +void FadeButton::activateOnce() +{ + if (activeNotes == 0) { activate(); } +} + + + + void FadeButton::noteEnd() { if (activeNotes <= 0) @@ -97,6 +105,7 @@ void FadeButton::noteEnd() + void FadeButton::paintEvent(QPaintEvent * _pe) { QColor col = m_normalColor; @@ -145,7 +154,7 @@ QColor FadeButton::fadeToColor(QColor startCol, QColor endCol, QTime timer, floa QColor col; const float state = 1 - timer.elapsed() / duration; - const int r = (int)(endCol.red() * (1.0f - state) + const int r = (int)(endCol.red() * (1.0f - state) + startCol.red() * state); const int g = (int)(endCol.green() * (1.0f - state) + startCol.green() * state); diff --git a/src/gui/widgets/Graph.cpp b/src/gui/widgets/Graph.cpp index 4710089dd1a..773a6f51b50 100644 --- a/src/gui/widgets/Graph.cpp +++ b/src/gui/widgets/Graph.cpp @@ -235,8 +235,9 @@ void Graph::drawLineAt( int _x, int _y, int _lastx ) model()->drawSampleAt( sample_begin + i , val_begin + ((i ) * ystep)); } - - model()->samplesChanged( sample_begin, sample_end ); + // We've changed [sample_end, sample_begin) + // However, samplesChanged expects two end points + model()->samplesChanged(sample_begin, sample_end - 1); } void Graph::changeSampleAt( int _x, int _y ) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index ac2a7f45166..52fb1044a27 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -996,7 +996,6 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV m_activityIndicator, SLOT( activate() ) ); connect( _it, SIGNAL( endNote() ), m_activityIndicator, SLOT( noteEnd() ) ); - connect( &_it->m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteChanged() ) ); setModel( _it ); } @@ -1225,22 +1224,6 @@ void InstrumentTrackView::midiConfigChanged() -void InstrumentTrackView::muteChanged() -{ - if(model()->m_mutedModel.value() ) - { - m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, - QPalette::Highlight ) ); - } else - { - m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, - QPalette::BrightText ) ); - } -} - - - - //FIXME: This is identical to SampleTrackView::createFxMenu QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) { diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index 72f63bb05b5..f377e35cfa3 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -585,20 +585,19 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) -SampleTrack::SampleTrack( TrackContainer* tc ) : - Track( Track::SampleTrack, tc ), - m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 0.1f, this, - tr( "Volume" ) ), - m_panningModel( DefaultPanning, PanningLeft, PanningRight, 0.1f, - this, tr( "Panning" ) ), - m_effectChannelModel( 0, 0, 0, this, tr( "FX channel" ) ), - m_audioPort( tr( "Sample track" ), true, &m_volumeModel, &m_panningModel, &m_mutedModel ) +SampleTrack::SampleTrack(TrackContainer* tc) : + Track(Track::SampleTrack, tc), + m_volumeModel(DefaultVolume, MinVolume, MaxVolume, 0.1f, this, tr("Volume")), + m_panningModel(DefaultPanning, PanningLeft, PanningRight, 0.1f, this, tr("Panning")), + m_effectChannelModel(0, 0, 0, this, tr("FX channel")), + m_audioPort(tr("Sample track"), true, &m_volumeModel, &m_panningModel, &m_mutedModel), + m_isPlaying(false) { - setName( tr( "Sample track" ) ); - m_panningModel.setCenterValue( DefaultPanning ); - m_effectChannelModel.setRange( 0, Engine::fxMixer()->numChannels()-1, 1); + setName(tr("Sample track")); + m_panningModel.setCenterValue(DefaultPanning); + m_effectChannelModel.setRange(0, Engine::fxMixer()->numChannels()-1, 1); - connect( &m_effectChannelModel, SIGNAL( dataChanged() ), this, SLOT( updateEffectChannel() ) ); + connect(&m_effectChannelModel, SIGNAL(dataChanged()), this, SLOT(updateEffectChannel())); } @@ -622,6 +621,10 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, ::BBTrack * bb_track = NULL; if( _tco_num >= 0 ) { + if (_start > getTCO(_tco_num)->length()) + { + setPlaying(false); + } if( _start != 0 ) { return false; @@ -630,10 +633,12 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, if (trackContainer() == (TrackContainer*)Engine::getBBTrackContainer()) { bb_track = BBTrack::findBBTrack( _tco_num ); + setPlaying(true); } } else { + bool nowPlaying = false; for( int i = 0; i < numOfTCOs(); ++i ) { TrackContentObject * tco = getTCO( i ); @@ -657,6 +662,7 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, sTco->setSamplePlayLength( samplePlayLength ); tcos.push_back( sTco ); sTco->setIsPlaying( true ); + nowPlaying = true; } } } @@ -664,7 +670,9 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, { sTco->setIsPlaying( false ); } + nowPlaying = nowPlaying || sTco->isPlaying(); } + setPlaying(nowPlaying); } for( tcoVector::Iterator it = tcos.begin(); it != tcos.end(); ++it ) @@ -826,6 +834,18 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : m_panningKnob->setLabel( tr( "PAN" ) ); m_panningKnob->show(); + m_activityIndicator = new FadeButton( + QApplication::palette().color(QPalette::Active, QPalette::Background), + QApplication::palette().color(QPalette::Active, QPalette::BrightText), + QApplication::palette().color(QPalette::Active, QPalette::BrightText).darker(), + getTrackSettingsWidget() + ); + m_activityIndicator->setGeometry(settingsWidgetWidth - 2 * 24 - 11, 2, 8, 28); + m_activityIndicator->show(); + connect(_t, SIGNAL(playingChanged()), this, SLOT(updateIndicator())); + connect(Engine::getSong(), SIGNAL(stopped()), + this, SLOT(stopPlaying())); + setModel( _t ); m_window = new SampleTrackWindow(this); @@ -835,6 +855,15 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : +void SampleTrackView::updateIndicator() +{ + if (model()->isPlaying()) { m_activityIndicator->activateOnce(); } + else { m_activityIndicator->noteEnd(); } +} + + + + SampleTrackView::~SampleTrackView() { if(m_window != NULL)