diff --git a/data/themes/default/pat_rec.png b/data/themes/default/pat_rec.png new file mode 100644 index 000000000..5c0ed9455 Binary files /dev/null and b/data/themes/default/pat_rec.png differ diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 4a1e6d2b5..10ee252e9 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -133,7 +133,6 @@ public: float controllerValue( int frameOffset ) const; - template T initValue() const { diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h index ca2ff2695..aea64947e 100644 --- a/include/AutomationPattern.h +++ b/include/AutomationPattern.h @@ -155,13 +155,21 @@ public: static AutomationPattern * globalAutomationPattern( AutomatableModel * _m ); static void resolveAllIDs(); + bool isRecording() const + { + return m_isRecording; + } + + void setRecording( const bool b ) + { + m_isRecording = b; + } public slots: void clear(); void openInAutomationEditor(); void objectDestroyed( jo_id_t ); - private: void cleanObjects(); void generateTangents(); @@ -179,6 +187,9 @@ private: ProgressionTypes m_progressionType; bool m_dragging; + + bool m_isRecording; + float m_lastRecordedValue; static const float DEFAULT_MIN_VALUE; static const float DEFAULT_MAX_VALUE; diff --git a/include/AutomationPatternView.h b/include/AutomationPatternView.h index 73b2a7d9e..382c28375 100644 --- a/include/AutomationPatternView.h +++ b/include/AutomationPatternView.h @@ -50,7 +50,7 @@ protected slots: void resetName(); void changeName(); void disconnectObject( QAction * _a ); - + void toggleRecording(); protected: virtual void constructContextMenu( QMenu * ); @@ -69,6 +69,8 @@ private: AutomationPattern * m_pat; QPixmap m_paintPixmap; bool m_needsUpdate; + + static QPixmap * s_pat_rec; void scaleTimemapToFit( float oldMin, float oldMax ); } ; diff --git a/include/track.h b/include/track.h index 07ae52d6e..8139ea869 100644 --- a/include/track.h +++ b/include/track.h @@ -373,7 +373,8 @@ private slots: void cloneTrack(); void removeTrack(); void updateMenu(); - + void recordingOn(); + void recordingOff(); private: static QPixmap * s_grip; diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index 0f38b34d9..49f154732 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -47,7 +47,9 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) : m_objects(), m_tension( 1.0 ), m_progressionType( DiscreteProgression ), - m_dragging( false ) + m_dragging( false ), + m_isRecording( false ), + m_lastRecordedValue( 0 ) { changeLength( MidiTime( 1, 0 ) ); } @@ -469,27 +471,44 @@ const QString AutomationPattern::name() const -void AutomationPattern::processMidiTime( const MidiTime & _time ) +void AutomationPattern::processMidiTime( const MidiTime & time ) { - if( _time >= 0 && hasAutomation() ) + if( ! isRecording() ) { - const float val = valueAt( _time ); - for( objectVector::iterator it = m_objects.begin(); - it != m_objects.end(); ++it ) + if( time >= 0 && hasAutomation() ) { - if( *it ) + const float val = valueAt( time ); + for( objectVector::iterator it = m_objects.begin(); + it != m_objects.end(); ++it ) { - ( *it )->setAutomatedValue( val ); - } + if( *it ) + { + ( *it )->setAutomatedValue( val ); + } + } + } + } + else + { + if( time >= 0 && ! m_objects.isEmpty() ) + { + const float value = static_cast( firstObject()->value() ); + if( value != m_lastRecordedValue ) + { + putValue( time, value, true ); + m_lastRecordedValue = value; + } + else if( valueAt( time ) != value ) + { + removeValue( time, false ); + } } } } - - trackContentObjectView * AutomationPattern::createView( trackView * _tv ) { return new AutomationPatternView( this, _tv ); diff --git a/src/core/track.cpp b/src/core/track.cpp index d75cc91b4..0c04ff369 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -1479,6 +1479,9 @@ void trackOperationsWidget::removeTrack() * * For all track types, we have the Clone and Remove options. * For instrument-tracks we also offer the MIDI-control-menu + * For automation tracks, extra options: turn on/off recording + * on all TCOs (same should be added for sample tracks when + * sampletrack recording is implemented) */ void trackOperationsWidget::updateMenu() { @@ -1497,11 +1500,45 @@ void trackOperationsWidget::updateMenu() to_menu->addMenu( dynamic_cast( m_trackView )->midiMenu() ); } + if( dynamic_cast( m_trackView ) ) + { + to_menu->addAction( tr( "Turn all recording on" ), this, SLOT( recordingOn() ) ); + to_menu->addAction( tr( "Turn all recording off" ), this, SLOT( recordingOff() ) ); + } } +void trackOperationsWidget::recordingOn() +{ + AutomationTrackView * atv = dynamic_cast( m_trackView ); + if( atv ) + { + const track::tcoVector & tcov = atv->getTrack()->getTCOs(); + for( track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); it++ ) + { + AutomationPattern * ap = dynamic_cast( *it ); + if( ap ) { ap->setRecording( true ); } + } + atv->update(); + } +} +void trackOperationsWidget::recordingOff() +{ + AutomationTrackView * atv = dynamic_cast( m_trackView ); + if( atv ) + { + const track::tcoVector & tcov = atv->getTrack()->getTCOs(); + for( track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); it++ ) + { + AutomationPattern * ap = dynamic_cast( *it ); + if( ap ) { ap->setRecording( false ); } + } + atv->update(); + } +} + // =========================================================================== // track diff --git a/src/gui/AutomationPatternView.cpp b/src/gui/AutomationPatternView.cpp index baa19376c..7f0f22194 100644 --- a/src/gui/AutomationPatternView.cpp +++ b/src/gui/AutomationPatternView.cpp @@ -38,6 +38,7 @@ #include "tooltip.h" +QPixmap * AutomationPatternView::s_pat_rec = NULL; AutomationPatternView::AutomationPatternView( AutomationPattern * _pattern, trackView * _parent ) : @@ -58,6 +59,9 @@ AutomationPatternView::AutomationPatternView( AutomationPattern * _pattern, toolTip::add( this, tr( "double-click to open this pattern in " "automation editor" ) ); setStyle( QApplication::style() ); + + if( s_pat_rec == NULL ) { s_pat_rec = new QPixmap( embed::getIconPixmap( + "pat_rec" ) ); } } @@ -134,6 +138,11 @@ void AutomationPatternView::disconnectObject( QAction * _a ) } +void AutomationPatternView::toggleRecording() +{ + m_pat->setRecording( ! m_pat->isRecording() ); + update(); +} void AutomationPatternView::constructContextMenu( QMenu * _cm ) @@ -156,6 +165,9 @@ void AutomationPatternView::constructContextMenu( QMenu * _cm ) _cm->addAction( embed::getIconPixmap( "edit_rename" ), tr( "Change name" ), this, SLOT( changeName() ) ); + _cm->addAction( embed::getIconPixmap( "record" ), + tr( "Set/clear record" ), + this, SLOT( toggleRecording() ) ); if( !m_pat->m_objects.isEmpty() ) { _cm->addSeparator(); @@ -236,12 +248,6 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) p.setPen( c.lighter( 130 ) ); p.drawRect( 1, 1, width()-3, height()-3 ); - p.setBrush( QBrush() ); - if( engine::automationEditor()->currentPattern() == m_pat ) - p.setPen( c.lighter( 130 ) ); - else - p.setPen( c.darker( 300 ) ); - p.drawRect( 0, 0, width()-1, height()-1 ); const float ppt = fixedTCOs() ? ( parentWidget()->width() - 2 * TCO_BORDER_WIDTH ) @@ -310,6 +316,22 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) } p.resetMatrix(); + + // recording icon for when recording automation + if( m_pat->isRecording() ) + { + p.drawPixmap( 4, 14, *s_pat_rec ); + } + + // outer edge + p.setBrush( QBrush() ); + if( engine::automationEditor()->currentPattern() == m_pat ) + p.setPen( c.lighter( 130 ) ); + else + p.setPen( c.darker( 300 ) ); + p.drawRect( 0, 0, width()-1, height()-1 ); + + // pattern name p.setFont( pointSize<8>( p.font() ) ); QColor text_color = ( m_pat->isMuted() || m_pat->getTrack()->isMuted() ) @@ -327,6 +349,7 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) embed::getIconPixmap( "muted", 16, 16 ) ); } + p.end(); _p.drawPixmap( 0, 0, m_paintPixmap ); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index b5359bbd2..b3c873b68 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -388,6 +388,12 @@ void MainWindow::finalize() SLOT( exportProject() ), m_toolBar ); + toolButton * whatsthis = new toolButton( + embed::getIconPixmap( "whatsthis" ), + tr( "What's this?" ), + this, SLOT( enterWhatsThisMode() ), + m_toolBar ); + m_toolBarLayout->setColumnMinimumWidth( 0, 5 ); m_toolBarLayout->addWidget( project_new, 0, 1 ); @@ -396,7 +402,7 @@ void MainWindow::finalize() m_toolBarLayout->addWidget( project_open_recent, 0, 4 ); m_toolBarLayout->addWidget( project_save, 0, 5 ); m_toolBarLayout->addWidget( project_export, 0, 6 ); - + m_toolBarLayout->addWidget( whatsthis, 0, 7 ); // window-toolbar diff --git a/src/gui/PianoRoll.cpp b/src/gui/PianoRoll.cpp index bfe20c867..b89799690 100644 --- a/src/gui/PianoRoll.cpp +++ b/src/gui/PianoRoll.cpp @@ -2247,7 +2247,8 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * _me ) } } else if( ( edit_note == true || m_action == ActionChangeNoteProperty ) && - ( _me->buttons() & Qt::LeftButton || _me->buttons() & Qt::MiddleButton ) ) + ( _me->buttons() & Qt::LeftButton || _me->buttons() & Qt::MiddleButton + || ( _me->buttons() & Qt::RightButton && _me->modifiers() & Qt::ShiftModifier ) ) ) { // editing note properties