do not disable automation when just editing first point of an automation pattern (closes #2146230) (stable backport)
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/branches/lmms/stable-0.4@1908 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
11
ChangeLog
11
ChangeLog
@@ -1,3 +1,14 @@
|
||||
2008-12-11 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* include/automation_pattern.h:
|
||||
* src/core/automation_pattern.cpp:
|
||||
do not disable automation when just editing first point of an
|
||||
automation pattern (closes #2146230)
|
||||
|
||||
* include/automation_pattern_view.h:
|
||||
* src/gui/automation_pattern_view.cpp:
|
||||
splitted view component out of automation_pattern.*
|
||||
|
||||
2008-12-10 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/vst_base/communication.h:
|
||||
|
||||
@@ -123,44 +123,4 @@ private:
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
class automationPatternView : public trackContentObjectView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
automationPatternView( automationPattern * _pat, trackView * _parent );
|
||||
virtual ~automationPatternView();
|
||||
|
||||
|
||||
public slots:
|
||||
virtual void update( void );
|
||||
|
||||
|
||||
protected slots:
|
||||
void resetName( void );
|
||||
void changeName( void );
|
||||
void disconnectObject( QAction * _a );
|
||||
|
||||
|
||||
protected:
|
||||
virtual void constructContextMenu( QMenu * );
|
||||
virtual void mouseDoubleClickEvent( QMouseEvent * _me );
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
virtual void resizeEvent( QResizeEvent * _re )
|
||||
{
|
||||
m_needsUpdate = true;
|
||||
trackContentObjectView::resizeEvent( _re );
|
||||
}
|
||||
virtual void dragEnterEvent( QDragEnterEvent * _dee );
|
||||
virtual void dropEvent( QDropEvent * _de );
|
||||
|
||||
|
||||
private:
|
||||
automationPattern * m_pat;
|
||||
QPixmap m_paintPixmap;
|
||||
bool m_needsUpdate;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,20 +30,12 @@
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
#include "automation_pattern.h"
|
||||
#include "automation_track.h"
|
||||
#include "automation_pattern_view.h"
|
||||
#include "automation_editor.h"
|
||||
#include "bb_track_container.h"
|
||||
#include "embed.h"
|
||||
#include "engine.h"
|
||||
#include "gui_templates.h"
|
||||
#include "note.h"
|
||||
#include "automation_track.h"
|
||||
#include "project_journal.h"
|
||||
#include "rename_dialog.h"
|
||||
#include "bb_track_container.h"
|
||||
#include "song.h"
|
||||
#include "string_pair_drag.h"
|
||||
#include "templates.h"
|
||||
#include "tooltip.h"
|
||||
#include "track_container.h"
|
||||
|
||||
|
||||
|
||||
@@ -161,20 +153,15 @@ midiTime automationPattern::putValue( const midiTime & _time,
|
||||
const float _value,
|
||||
const bool _quant_pos )
|
||||
{
|
||||
midiTime new_time = _quant_pos && engine::getAutomationEditor() ?
|
||||
midiTime newTime = _quant_pos && engine::getAutomationEditor() ?
|
||||
note::quantized( _time,
|
||||
engine::getAutomationEditor()->quantization() ) :
|
||||
_time;
|
||||
|
||||
m_timeMap[new_time] = _value;
|
||||
m_timeMap[newTime] = _value;
|
||||
|
||||
if( new_time != 0 )
|
||||
if( newTime == 0 )
|
||||
{
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hasAutomation = false;
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); )
|
||||
{
|
||||
@@ -190,6 +177,29 @@ midiTime automationPattern::putValue( const midiTime & _time,
|
||||
}
|
||||
}
|
||||
|
||||
// just one automation value?
|
||||
if( m_timeMap.size() == 1 )
|
||||
{
|
||||
m_hasAutomation = m_objects.isEmpty(); // usually false
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); ++it )
|
||||
{
|
||||
// default value differs from current value?
|
||||
if( *it && _value != ( *it )->initValue<float>() )
|
||||
{
|
||||
// then enable automating this object
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in all other cases assume we have automation
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
changeLength( length() );
|
||||
@@ -197,7 +207,7 @@ midiTime automationPattern::putValue( const midiTime & _time,
|
||||
|
||||
emit dataChanged();
|
||||
|
||||
return new_time;
|
||||
return newTime;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,15 +219,20 @@ void automationPattern::removeValue( const midiTime & _time )
|
||||
{
|
||||
m_timeMap.remove( _time );
|
||||
|
||||
if( m_timeMap.size() <= 1 )
|
||||
if( m_timeMap.size() == 1 )
|
||||
{
|
||||
const float val = m_timeMap[0];
|
||||
m_hasAutomation = false;
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
( *it )->setValue( m_timeMap[0] );
|
||||
( *it )->setValue( val );
|
||||
if( ( *it )->initValue<float>() != val )
|
||||
{
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
else
|
||||
@@ -272,7 +287,7 @@ void automationPattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
for( objectVector::const_iterator it = m_objects.begin();
|
||||
it != m_objects.end(); ++it )
|
||||
{
|
||||
if( *it != NULL )
|
||||
if( *it )
|
||||
{
|
||||
QDomElement element = _doc.createElement( "object" );
|
||||
element.setAttribute( "id", ( *it )->id() );
|
||||
@@ -522,301 +537,5 @@ void automationPattern::objectDestroyed( jo_id_t _id )
|
||||
|
||||
|
||||
|
||||
|
||||
automationPatternView::automationPatternView( automationPattern * _pattern,
|
||||
trackView * _parent ) :
|
||||
trackContentObjectView( _pattern, _parent ),
|
||||
m_pat( _pattern ),
|
||||
m_paintPixmap(),
|
||||
m_needsUpdate( true )
|
||||
{
|
||||
connect( m_pat, SIGNAL( dataChanged() ),
|
||||
this, SLOT( update() ) );
|
||||
|
||||
setAttribute( Qt::WA_OpaquePaintEvent, true );
|
||||
setFixedHeight( parentWidget()->height() - 2 );
|
||||
setAutoResizeEnabled( false );
|
||||
|
||||
toolTip::add( this, tr( "double-click to open this pattern in "
|
||||
"automation editor" ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
automationPatternView::~automationPatternView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::update( void )
|
||||
{
|
||||
m_needsUpdate = true;
|
||||
if( fixedTCOs() )
|
||||
{
|
||||
m_pat->changeLength( m_pat->length() );
|
||||
}
|
||||
trackContentObjectView::update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::resetName( void )
|
||||
{
|
||||
m_pat->setName( QString::null );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::changeName( void )
|
||||
{
|
||||
QString s = m_pat->name();
|
||||
renameDialog rename_dlg( s );
|
||||
rename_dlg.exec();
|
||||
m_pat->setName( s );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::disconnectObject( QAction * _a )
|
||||
{
|
||||
journallingObject * j = engine::getProjectJournal()->
|
||||
getJournallingObject( _a->data().toInt() );
|
||||
if( j && dynamic_cast<automatableModel *>( j ) )
|
||||
{
|
||||
m_pat->m_objects.erase( qFind( m_pat->m_objects.begin(),
|
||||
m_pat->m_objects.end(),
|
||||
dynamic_cast<automatableModel *>( j ) ) );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::constructContextMenu( QMenu * _cm )
|
||||
{
|
||||
QAction * a = new QAction( embed::getIconPixmap( "automation" ),
|
||||
tr( "Open in Automation editor" ), _cm );
|
||||
_cm->insertAction( _cm->actions()[0], a );
|
||||
connect( a, SIGNAL( triggered( bool ) ),
|
||||
m_pat, SLOT( openInAutomationEditor() ) );
|
||||
_cm->insertSeparator( _cm->actions()[1] );
|
||||
|
||||
_cm->addSeparator();
|
||||
|
||||
_cm->addAction( embed::getIconPixmap( "edit_erase" ),
|
||||
tr( "Clear" ), m_pat, SLOT( clear() ) );
|
||||
_cm->addSeparator();
|
||||
|
||||
_cm->addAction( embed::getIconPixmap( "reload" ), tr( "Reset name" ),
|
||||
this, SLOT( resetName() ) );
|
||||
_cm->addAction( embed::getIconPixmap( "edit_rename" ),
|
||||
tr( "Change name" ),
|
||||
this, SLOT( changeName() ) );
|
||||
if( !m_pat->m_objects.isEmpty() )
|
||||
{
|
||||
_cm->addSeparator();
|
||||
QMenu * m = new QMenu( tr( "%1 Connections" ).
|
||||
arg( m_pat->m_objects.count() ), _cm );
|
||||
for( automationPattern::objectVector::iterator it =
|
||||
m_pat->m_objects.begin();
|
||||
it != m_pat->m_objects.end(); ++it )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
a = new QAction( tr( "Disconnect \"%1\"" ).
|
||||
arg( ( *it )->fullDisplayName() ), m );
|
||||
a->setData( ( *it )->id() );
|
||||
m->addAction( a );
|
||||
}
|
||||
}
|
||||
connect( m, SIGNAL( triggered( QAction * ) ),
|
||||
this, SLOT( disconnectObject( QAction * ) ) );
|
||||
_cm->addMenu( m );
|
||||
}
|
||||
|
||||
_cm->addSeparator();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::mouseDoubleClickEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() != Qt::LeftButton )
|
||||
{
|
||||
_me->ignore();
|
||||
return;
|
||||
}
|
||||
m_pat->openInAutomationEditor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::paintEvent( QPaintEvent * )
|
||||
{
|
||||
if( m_needsUpdate == false )
|
||||
{
|
||||
QPainter p( this );
|
||||
p.drawPixmap( 0, 0, m_paintPixmap );
|
||||
return;
|
||||
}
|
||||
|
||||
m_needsUpdate = false;
|
||||
|
||||
if( m_paintPixmap.isNull() == true || m_paintPixmap.size() != size() )
|
||||
{
|
||||
m_paintPixmap = QPixmap( size() );
|
||||
}
|
||||
|
||||
QPainter p( &m_paintPixmap );
|
||||
|
||||
QLinearGradient lingrad( 0, 0, 0, height() );
|
||||
const QColor c = isSelected() ? QColor( 0, 0, 224 ) :
|
||||
QColor( 96, 96, 96 );
|
||||
lingrad.setColorAt( 0, c );
|
||||
lingrad.setColorAt( 0.5, Qt::black );
|
||||
lingrad.setColorAt( 1, c );
|
||||
p.setBrush( lingrad );
|
||||
p.setPen( QColor( 0, 0, 0 ) );
|
||||
p.drawRect( QRect( 0, 0, width() - 1, height() - 1 ) );
|
||||
|
||||
const float ppt = fixedTCOs() ?
|
||||
( parentWidget()->width() - 2 * TCO_BORDER_WIDTH )
|
||||
/ (float) m_pat->length().getTact() :
|
||||
pixelsPerTact();
|
||||
|
||||
const int x_base = TCO_BORDER_WIDTH;
|
||||
p.setPen( QColor( 0, 0, 0 ) );
|
||||
|
||||
for( tact t = 1; t < m_pat->length().getTact(); ++t )
|
||||
{
|
||||
p.drawLine( x_base + static_cast<int>( ppt * t ) - 1,
|
||||
TCO_BORDER_WIDTH, x_base + static_cast<int>(
|
||||
ppt * t ) - 1, 5 );
|
||||
p.drawLine( x_base + static_cast<int>( ppt * t ) - 1,
|
||||
height() - ( 4 + 2 * TCO_BORDER_WIDTH ),
|
||||
x_base + static_cast<int>( ppt * t ) - 1,
|
||||
height() - 2 * TCO_BORDER_WIDTH );
|
||||
}
|
||||
|
||||
const float min = m_pat->firstObject()->minValue<float>();
|
||||
const float max = m_pat->firstObject()->maxValue<float>();
|
||||
|
||||
const float y_scale = max - min;
|
||||
const float h = ( height()-2*TCO_BORDER_WIDTH ) / y_scale;
|
||||
|
||||
p.translate( 0.0f, max * height() / y_scale-1 );
|
||||
p.scale( 1.0f, -h );
|
||||
|
||||
QLinearGradient lin2grad( 0, min, 0, max );
|
||||
const QColor cl = QColor( 255, 224, 0 );
|
||||
const QColor cd = QColor( 229, 158, 0 );
|
||||
|
||||
lin2grad.setColorAt( 1, cl );
|
||||
lin2grad.setColorAt( 0, cd );
|
||||
|
||||
for( automationPattern::timeMap::const_iterator it =
|
||||
m_pat->getTimeMap().begin();
|
||||
it != m_pat->getTimeMap().end(); ++it )
|
||||
{
|
||||
const float x1 = 2 * x_base + it.key() * ppt /
|
||||
midiTime::ticksPerTact();
|
||||
float x2;
|
||||
if( it+1 != m_pat->getTimeMap().end() )
|
||||
{
|
||||
x2 = (it+1).key() * ppt / midiTime::ticksPerTact() + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
x2 = (float)( width() - TCO_BORDER_WIDTH );
|
||||
}
|
||||
p.fillRect( QRectF( x1, 0.0f, x2-x1, it.value() ),
|
||||
lin2grad );
|
||||
}
|
||||
|
||||
p.resetMatrix();
|
||||
p.setFont( pointSize<7>( p.font() ) );
|
||||
if( m_pat->isMuted() || m_pat->getTrack()->isMuted() )
|
||||
{
|
||||
p.setPen( QColor( 192, 192, 192 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
p.setPen( QColor( 0, 64, 255 ) );
|
||||
}
|
||||
|
||||
p.drawText( 2, p.fontMetrics().height() - 1, m_pat->name() );
|
||||
|
||||
if( m_pat->isMuted() )
|
||||
{
|
||||
p.drawPixmap( 3, p.fontMetrics().height() + 1,
|
||||
embed::getIconPixmap( "muted", 16, 16 ) );
|
||||
}
|
||||
|
||||
p.end();
|
||||
|
||||
p.begin( this );
|
||||
p.drawPixmap( 0, 0, m_paintPixmap );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
stringPairDrag::processDragEnterEvent( _dee, "automatable_model" );
|
||||
if( !_dee->isAccepted() )
|
||||
{
|
||||
trackContentObjectView::dragEnterEvent( _dee );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void automationPatternView::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
QString type = stringPairDrag::decodeKey( _de );
|
||||
QString val = stringPairDrag::decodeValue( _de );
|
||||
if( type == "automatable_model" )
|
||||
{
|
||||
automatableModel * mod = dynamic_cast<automatableModel *>(
|
||||
engine::getProjectJournal()->
|
||||
getJournallingObject( val.toInt() ) );
|
||||
if( mod != NULL )
|
||||
{
|
||||
m_pat->addObject( mod );
|
||||
}
|
||||
update();
|
||||
|
||||
if( engine::getAutomationEditor() &&
|
||||
engine::getAutomationEditor()->currentPattern() ==
|
||||
m_pat )
|
||||
{
|
||||
engine::getAutomationEditor()->setCurrentPattern(
|
||||
m_pat );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trackContentObjectView::dropEvent( _de );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "moc_automation_pattern.cxx"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user