Merge pull request #237 from wongcc966422/issue27

Automation Tweaks and Bugfixes
This commit is contained in:
Tobias Doerffel
2014-02-02 05:41:45 -08:00
5 changed files with 170 additions and 83 deletions

View File

@@ -111,6 +111,16 @@ public:
return m_tangents;
}
inline float getMin() const
{
return firstObject()->minValue<float>();
}
inline float getMax() const
{
return firstObject()->maxValue<float>();
}
inline bool hasAutomation() const
{
return m_timeMap.isEmpty() == false;
@@ -169,6 +179,8 @@ private:
bool m_dragging;
static const float DEFAULT_MIN_VALUE = 0;
static const float DEFAULT_MAX_VALUE = 1;
friend class AutomationPatternView;

View File

@@ -66,6 +66,8 @@ private:
QPixmap m_paintPixmap;
bool m_needsUpdate;
void scaleTimemapToFit( float oldMin, float oldMax );
} ;

View File

@@ -84,8 +84,6 @@ AutomationPattern::~AutomationPattern()
void AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
{
bool addIt = true;
if( _search_dup )
{
for( objectVector::iterator it = m_objects.begin();
@@ -95,27 +93,26 @@ void AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
{
// Already exists
// TODO: Maybe let the user know in some non-annoying way
addIt = false;
break;
return;
}
}
}
if( addIt )
// the automation track is unconnected and there is nothing in the track
if( m_objects.isEmpty() && hasAutomation() == false )
{
// been empty before and model's current value is not its init value?
if( m_objects.isEmpty() && hasAutomation() == false && _obj->isAtInitValue() == false )
{
// then initialize first value
putValue( 0, _obj->value<float>(), false );
}
m_objects += _obj;
connect( _obj, SIGNAL( destroyed( jo_id_t ) ),
this, SLOT( objectDestroyed( jo_id_t ) ),
Qt::DirectConnection );
// then initialize first value
putValue( MidiTime(0), _obj->value<float>(), false );
}
m_objects += _obj;
connect( _obj, SIGNAL( destroyed( jo_id_t ) ),
this, SLOT( objectDestroyed( jo_id_t ) ),
Qt::DirectConnection );
emit dataChanged();
}
@@ -158,7 +155,7 @@ const AutomatableModel * AutomationPattern::firstObject() const
return m;
}
static FloatModel _fm( 0, 0, 1, 0.001 );
static FloatModel _fm( 0, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, 0.001 );
return &_fm;
}
@@ -584,18 +581,18 @@ void AutomationPattern::resolveAllIDs()
AutomationPattern * a = dynamic_cast<AutomationPattern *>( *j );
if( a )
{
for( QVector<jo_id_t>::Iterator k = a->m_idsToResolve.begin();
k != a->m_idsToResolve.end(); ++k )
{
JournallingObject * o = engine::projectJournal()->
journallingObject( *k );
if( o && dynamic_cast<AutomatableModel *>( o ) )
{
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
}
}
a->m_idsToResolve.clear();
a->dataChanged();
for( QVector<jo_id_t>::Iterator k = a->m_idsToResolve.begin();
k != a->m_idsToResolve.end(); ++k )
{
JournallingObject * o = engine::projectJournal()->
journallingObject( *k );
if( o && dynamic_cast<AutomatableModel *>( o ) )
{
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
}
}
a->m_idsToResolve.clear();
a->dataChanged();
}
}
}
@@ -639,6 +636,20 @@ void AutomationPattern::objectDestroyed( jo_id_t _id )
// case we had to remove ourselves if we're the global automation
// pattern of the destroyed object
m_idsToResolve += _id;
for( objectVector::Iterator objIt = m_objects.begin();
objIt != m_objects.end(); objIt++ )
{
Q_ASSERT( !(*objIt).isNull() );
if( (*objIt)->id() == _id )
{
//Assign to objIt so that this loop work even break; is removed.
objIt = m_objects.erase( objIt );
break;
}
}
emit dataChanged();
}
@@ -703,4 +714,6 @@ void AutomationPattern::generateTangents( timeMap::const_iterator it,
}
#include "moc_AutomationPattern.cxx"

View File

@@ -1546,72 +1546,76 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
{
int len_ticks = 4;
timeMap & time_map = m_pattern->getTimeMap();
timeMap::iterator it = time_map.begin();
p.setPen( QColor( 0xCF, 0xD9, 0xFF ) );
while( it+1 != time_map.end() )
//Don't bother doing/rendering anything if there is no automation points
if( time_map.size() > 0 )
{
// skip this section if it occurs completely before the
// visible area
int next_x = xCoordOfTick( (it+1).key() );
if( next_x < 0 )
timeMap::iterator it = time_map.begin();
p.setPen( QColor( 0xCF, 0xD9, 0xFF ) );
while( it+1 != time_map.end() )
{
++it;
continue;
}
// skip this section if it occurs completely before the
// visible area
int next_x = xCoordOfTick( (it+1).key() );
if( next_x < 0 )
{
++it;
continue;
}
int x = xCoordOfTick( it.key() );
if( x > width() )
{
break;
}
int x = xCoordOfTick( it.key() );
if( x > width() )
{
break;
}
bool is_selected = FALSE;
// if we're in move-mode, we may only draw
// values in selected area, that have originally
// been selected and not values that are now in
// selection because the user moved it...
if( m_editMode == MOVE )
{
if( m_selValuesForMove.contains( it.key() ) )
bool is_selected = FALSE;
// if we're in move-mode, we may only draw
// values in selected area, that have originally
// been selected and not values that are now in
// selection because the user moved it...
if( m_editMode == MOVE )
{
if( m_selValuesForMove.contains( it.key() ) )
{
is_selected = TRUE;
}
}
else if( it.value() >= selLevel_start &&
it.value() <= selLevel_end &&
it.key() >= sel_pos_start &&
it.key() + len_ticks <= sel_pos_end )
{
is_selected = TRUE;
}
}
else if( it.value() >= selLevel_start &&
it.value() <= selLevel_end &&
it.key() >= sel_pos_start &&
it.key() + len_ticks <= sel_pos_end )
{
is_selected = TRUE;
float *values = m_pattern->valuesAfter( it.key() );
for( int i = 0; i < (it+1).key() - it.key(); i++ )
{
drawLevelTick( p, it.key() + i, values[i],
is_selected );
}
delete [] values;
// Draw circle
drawAutomationPoint(p, it);
++it;
}
float *values = m_pattern->valuesAfter( it.key() );
for( int i = 0; i < (it+1).key() - it.key(); i++ )
{
drawLevelTick( p, it.key() + i, values[i],
is_selected );
}
delete [] values;
Q_ASSERT( it == time_map.end()-1 );
// Draw circle
for( int i = it.key(), x = xCoordOfTick( i ); x <= width();
i++, x = xCoordOfTick( i ) )
{
// TODO: Find out if the section after the last control
// point is able to be selected and if so set this
// boolean correctly
drawLevelTick( p, i, it.value(), false );
}
// Draw circle(the last one)
drawAutomationPoint(p, it);
++it;
}
Q_ASSERT( it == time_map.end()-1 );
for( int i = it.key(), x = xCoordOfTick( i ); x <= width();
i++, x = xCoordOfTick( i ) )
{
// TODO: Find out if the section after the last control
// point is able to be selected and if so set this
// boolean correctly
drawLevelTick( p, i, it.value(), false );
}
// Draw circle(the last one)
drawAutomationPoint(p, it);
}
else
{

View File

@@ -107,10 +107,26 @@ void AutomationPatternView::disconnectObject( QAction * _a )
journallingObject( _a->data().toInt() );
if( j && dynamic_cast<AutomatableModel *>( j ) )
{
float oldMin = m_pat->getMin();
float oldMax = m_pat->getMax();
m_pat->m_objects.erase( qFind( m_pat->m_objects.begin(),
m_pat->m_objects.end(),
dynamic_cast<AutomatableModel *>( j ) ) );
update();
//If automation editor is opened, update its display after disconnection
if( engine::automationEditor() )
{
engine::automationEditor()->updateAfterPatternChange();
}
//if there is no more connection connected to the AutomationPattern
if( m_pat->m_objects.size() == 0 )
{
//scale the points to fit the new min. and max. value
this->scaleTimemapToFit( oldMin, oldMax );
}
}
}
@@ -333,6 +349,14 @@ void AutomationPatternView::dropEvent( QDropEvent * _de )
{
engine::automationEditor()->setCurrentPattern( m_pat );
}
//This is the only model that's just added to AutomationPattern.
if( m_pat->m_objects.size() == 1 )
{
//scale the points to fit the new min. and max. value
this->scaleTimemapToFit( AutomationPattern::DEFAULT_MIN_VALUE,
AutomationPattern::DEFAULT_MAX_VALUE );
}
}
else
{
@@ -343,5 +367,37 @@ void AutomationPatternView::dropEvent( QDropEvent * _de )
/**
* @brief Preserves the auto points over different scale
*/
void AutomationPatternView::scaleTimemapToFit( float oldMin, float oldMax )
{
float newMin = m_pat->getMin();
float newMax = m_pat->getMax();
if( oldMin == newMin && oldMax == newMax )
{
return;
}
for( AutomationPattern::timeMap::iterator it = m_pat->m_timeMap.begin();
it != m_pat->m_timeMap.end(); ++it )
{
if( *it < oldMin )
{
*it = oldMin;
}
else if( *it > oldMax )
{
*it = oldMax;
}
*it = (*it-oldMin)*(newMax-newMin)/(oldMax-oldMin)+newMin;
}
m_pat->generateTangents();
}
#include "moc_AutomationPatternView.cxx"