mirror of
https://github.com/LMMS/lmms.git
synced 2026-01-25 14:58:07 -05:00
Merge pull request #203 from wongcc966422/issue1
Automation points are now draggable
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include "MidiTime.h"
|
||||
#include "AutomationPattern.h"
|
||||
#include "ComboBoxModel.h"
|
||||
#include "knob.h"
|
||||
|
||||
|
||||
class QPainter;
|
||||
@@ -103,7 +104,7 @@ protected:
|
||||
void getSelectedValues( timeMap & _selected_values );
|
||||
|
||||
void drawLine( int x0, float y0, int x1, float y1 );
|
||||
void disableTensionComboBox();
|
||||
void disableTensionKnob();
|
||||
|
||||
protected slots:
|
||||
void play();
|
||||
@@ -188,9 +189,8 @@ private:
|
||||
toolButton * m_discreteButton;
|
||||
toolButton * m_linearButton;
|
||||
toolButton * m_cubicHermiteButton;
|
||||
comboBox * m_tensionComboBox;
|
||||
ComboBoxModel m_tensionModel;
|
||||
ComboBoxModel m_tensionDisabledModel;
|
||||
knob * m_tensionKnob;
|
||||
FloatModel * m_tensionModel;
|
||||
|
||||
toolButton * m_cutButton;
|
||||
toolButton * m_copyButton;
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
}
|
||||
void setProgressionType( ProgressionTypes _new_progression_type );
|
||||
|
||||
inline QString getTension() const
|
||||
inline float getTension() const
|
||||
{
|
||||
return m_tension;
|
||||
}
|
||||
@@ -77,7 +77,19 @@ public:
|
||||
MidiTime putValue( const MidiTime & _time, const float _value,
|
||||
const bool _quant_pos = true );
|
||||
|
||||
void removeValue( const MidiTime & _time );
|
||||
void removeValue( const MidiTime & _time,
|
||||
const bool _quant_pos = true );
|
||||
|
||||
MidiTime setDragValue( const MidiTime & _time, const float _value,
|
||||
const bool _quant_pos = true );
|
||||
|
||||
void applyDragValue();
|
||||
|
||||
|
||||
bool isDragging() const
|
||||
{
|
||||
return m_dragging;
|
||||
}
|
||||
|
||||
inline const timeMap & getTimeMap() const
|
||||
{
|
||||
@@ -149,11 +161,14 @@ private:
|
||||
QVector<jo_id_t> m_idsToResolve;
|
||||
objectVector m_objects;
|
||||
timeMap m_timeMap; // actual values
|
||||
timeMap m_oldTimeMap; // old values for storing the values before setDragValue() is called.
|
||||
timeMap m_tangents; // slope at each point for calculating spline
|
||||
QString m_tension;
|
||||
float m_tension;
|
||||
bool m_hasAutomation;
|
||||
ProgressionTypes m_progressionType;
|
||||
|
||||
bool m_dragging;
|
||||
|
||||
|
||||
friend class AutomationPatternView;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ libdir=/usr/local/lib
|
||||
srcdir=.
|
||||
|
||||
# compiler names
|
||||
CC="gcc"
|
||||
CC="cc"
|
||||
CXX="c++"
|
||||
|
||||
# flags for C++ compiler:
|
||||
|
||||
@@ -42,8 +42,9 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
|
||||
trackContentObject( _auto_track ),
|
||||
m_autoTrack( _auto_track ),
|
||||
m_objects(),
|
||||
m_tension( "1.0" ),
|
||||
m_progressionType( DiscreteProgression )
|
||||
m_tension( 1.0 ),
|
||||
m_progressionType( DiscreteProgression ),
|
||||
m_dragging( false )
|
||||
{
|
||||
changeLength( MidiTime( 1, 0 ) );
|
||||
}
|
||||
@@ -142,7 +143,7 @@ void AutomationPattern::setTension( QString _new_tension )
|
||||
|
||||
if( ok && nt > -0.01 && nt < 1.01 )
|
||||
{
|
||||
m_tension = _new_tension;
|
||||
m_tension = _new_tension.toFloat();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,13 +216,19 @@ MidiTime AutomationPattern::putValue( const MidiTime & _time,
|
||||
|
||||
|
||||
|
||||
void AutomationPattern::removeValue( const MidiTime & _time )
|
||||
void AutomationPattern::removeValue( const MidiTime & _time,
|
||||
const bool _quant_pos )
|
||||
{
|
||||
cleanObjects();
|
||||
|
||||
m_timeMap.remove( _time );
|
||||
m_tangents.remove( _time );
|
||||
timeMap::const_iterator it = m_timeMap.lowerBound( _time );
|
||||
MidiTime newTime = _quant_pos && engine::automationEditor() ?
|
||||
note::quantized( _time,
|
||||
engine::automationEditor()->quantization() ) :
|
||||
_time;
|
||||
|
||||
m_timeMap.remove( newTime );
|
||||
m_tangents.remove( newTime );
|
||||
timeMap::const_iterator it = m_timeMap.lowerBound( newTime );
|
||||
if( it != m_timeMap.begin() )
|
||||
{
|
||||
it--;
|
||||
@@ -240,6 +247,55 @@ void AutomationPattern::removeValue( const MidiTime & _time )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the position of the point that is being draged.
|
||||
* Calling this function will also automatically set m_dragging to true,
|
||||
* which applyDragValue() have to be called to m_dragging.
|
||||
* @param the time(x position) of the point being dragged
|
||||
* @param the value(y position) of the point being dragged
|
||||
* @param true to snip x position
|
||||
* @return
|
||||
*/
|
||||
MidiTime AutomationPattern::setDragValue( const MidiTime & _time, const float _value,
|
||||
const bool _quant_pos )
|
||||
{
|
||||
if( m_dragging == false )
|
||||
{
|
||||
MidiTime newTime = _quant_pos && engine::automationEditor() ?
|
||||
note::quantized( _time,
|
||||
engine::automationEditor()->quantization() ) :
|
||||
_time;
|
||||
this->removeValue( newTime );
|
||||
m_oldTimeMap = m_timeMap;
|
||||
m_dragging = true;
|
||||
}
|
||||
|
||||
//Restore to the state before it the point were being dragged
|
||||
m_timeMap = m_oldTimeMap;
|
||||
|
||||
for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); it++ )
|
||||
{
|
||||
generateTangents(it, 3);
|
||||
}
|
||||
|
||||
return this->putValue( _time, _value, _quant_pos );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief After the point is dragged, this function is called to apply the change.
|
||||
*/
|
||||
void AutomationPattern::applyDragValue()
|
||||
{
|
||||
m_dragging = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float AutomationPattern::valueAt( const MidiTime & _time ) const
|
||||
{
|
||||
if( m_timeMap.isEmpty() )
|
||||
@@ -291,10 +347,8 @@ float AutomationPattern::valueAt( timeMap::const_iterator v, int offset ) const
|
||||
// tangents _m1 and _m2
|
||||
int numValues = ((v+1).key() - v.key());
|
||||
float t = (float) offset / (float) numValues;
|
||||
float m1 = (m_tangents[v.key()]) * numValues
|
||||
* m_tension.toFloat();
|
||||
float m2 = (m_tangents[(v+1).key()]) * numValues
|
||||
* m_tension.toFloat();
|
||||
float m1 = (m_tangents[v.key()]) * numValues * m_tension;
|
||||
float m2 = (m_tangents[(v+1).key()]) * numValues * m_tension;
|
||||
|
||||
return ( 2*pow(t,3) - 3*pow(t,2) + 1 ) * v.value()
|
||||
+ ( pow(t,3) - 2*pow(t,2) + t) * m1
|
||||
@@ -334,7 +388,7 @@ void AutomationPattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
_this.setAttribute( "len", trackContentObject::length() );
|
||||
_this.setAttribute( "name", name() );
|
||||
_this.setAttribute( "prog", QString::number( progressionType() ) );
|
||||
_this.setAttribute( "tens", getTension() );
|
||||
_this.setAttribute( "tens", QString::number( getTension() ) );
|
||||
|
||||
for( timeMap::const_iterator it = m_timeMap.begin();
|
||||
it != m_timeMap.end(); ++it )
|
||||
|
||||
@@ -200,7 +200,8 @@ AutomationEditor::AutomationEditor() :
|
||||
m_toolBar );
|
||||
m_eraseButton->setCheckable( TRUE );
|
||||
|
||||
m_selectButton = new toolButton( embed::getIconPixmap(
|
||||
//TODO: m_selectButton and m_moveButton are broken.
|
||||
/*m_selectButton = new toolButton( embed::getIconPixmap(
|
||||
"edit_select" ),
|
||||
tr( "Select mode (Shift+S)" ),
|
||||
this, SLOT( selectButtonToggled() ),
|
||||
@@ -211,13 +212,13 @@ AutomationEditor::AutomationEditor() :
|
||||
tr( "Move selection mode (Shift+M)" ),
|
||||
this, SLOT( moveButtonToggled() ),
|
||||
m_toolBar );
|
||||
m_moveButton->setCheckable( TRUE );
|
||||
m_moveButton->setCheckable( TRUE );*/
|
||||
|
||||
QButtonGroup * tool_button_group = new QButtonGroup( this );
|
||||
tool_button_group->addButton( m_drawButton );
|
||||
tool_button_group->addButton( m_eraseButton );
|
||||
tool_button_group->addButton( m_selectButton );
|
||||
tool_button_group->addButton( m_moveButton );
|
||||
//tool_button_group->addButton( m_selectButton );
|
||||
//tool_button_group->addButton( m_moveButton );
|
||||
tool_button_group->setExclusive( TRUE );
|
||||
|
||||
m_drawButton->setWhatsThis(
|
||||
@@ -230,7 +231,7 @@ AutomationEditor::AutomationEditor() :
|
||||
tr( "Click here and erase-mode will be activated. In this "
|
||||
"mode you can erase single values. You can also press "
|
||||
"'Shift+E' on your keyboard to activate this mode." ) );
|
||||
m_selectButton->setWhatsThis(
|
||||
/*m_selectButton->setWhatsThis(
|
||||
tr( "Click here and select-mode will be activated. In this "
|
||||
"mode you can select values. This is necessary "
|
||||
"if you want to cut, copy, paste, delete, or move "
|
||||
@@ -240,7 +241,7 @@ AutomationEditor::AutomationEditor() :
|
||||
tr( "If you click here, move-mode will be activated. In this "
|
||||
"mode you can move the values you selected in select-"
|
||||
"mode. You can also press 'Shift+M' on your keyboard "
|
||||
"to activate this mode." ) );
|
||||
"to activate this mode." ) );*/
|
||||
|
||||
m_discreteButton = new toolButton( embed::getIconPixmap(
|
||||
"progression_discrete" ),
|
||||
@@ -266,21 +267,13 @@ AutomationEditor::AutomationEditor() :
|
||||
m_cubicHermiteButton->setCheckable( true );
|
||||
|
||||
// setup tension-stuff
|
||||
m_tensionComboBox = new comboBox( m_toolBar );
|
||||
m_tensionComboBox->setFixedSize( 60, 22 );
|
||||
m_tensionKnob = new knob( knobSmall_17, this, "Tension" );
|
||||
m_tensionModel = new FloatModel(1.0, 0.0, 1.0, 0.01);
|
||||
connect( m_tensionModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( tensionChanged() ) );
|
||||
|
||||
for( int i = 0; i < 4; ++i )
|
||||
{
|
||||
m_tensionModel.addItem( "0." + QString::number( 25 * i ) );
|
||||
}
|
||||
m_tensionModel.addItem( "1.0" );
|
||||
m_tensionModel.setValue( m_tensionModel.findText( "1.0" ) );
|
||||
|
||||
m_tensionDisabledModel.addItem( "-----" );
|
||||
disableTensionComboBox();
|
||||
|
||||
connect( &m_tensionModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( tensionChanged() ) );
|
||||
QLabel * tension_lbl = new QLabel( m_toolBar );
|
||||
tension_lbl->setText( tr("Tension: ") );
|
||||
|
||||
tool_button_group = new QButtonGroup( this );
|
||||
tool_button_group->addButton( m_discreteButton );
|
||||
@@ -397,14 +390,16 @@ AutomationEditor::AutomationEditor() :
|
||||
tb_layout->addSpacing( 10 );
|
||||
tb_layout->addWidget( m_drawButton );
|
||||
tb_layout->addWidget( m_eraseButton );
|
||||
tb_layout->addWidget( m_selectButton );
|
||||
tb_layout->addWidget( m_moveButton );
|
||||
//tb_layout->addWidget( m_selectButton );
|
||||
//tb_layout->addWidget( m_moveButton );
|
||||
tb_layout->addSpacing( 10 );
|
||||
tb_layout->addWidget( m_discreteButton );
|
||||
tb_layout->addWidget( m_linearButton );
|
||||
tb_layout->addWidget( m_cubicHermiteButton );
|
||||
tb_layout->addSpacing( 5 );
|
||||
tb_layout->addWidget( m_tensionComboBox );
|
||||
tb_layout->addWidget( tension_lbl );
|
||||
tb_layout->addSpacing( 5 );
|
||||
tb_layout->addWidget( m_tensionKnob );
|
||||
tb_layout->addSpacing( 10 );
|
||||
tb_layout->addWidget( m_cutButton );
|
||||
tb_layout->addWidget( m_copyButton );
|
||||
@@ -456,7 +451,7 @@ AutomationEditor::~AutomationEditor()
|
||||
{
|
||||
m_zoomingXModel.disconnect();
|
||||
m_zoomingYModel.disconnect();
|
||||
m_tensionModel.disconnect();
|
||||
m_tensionModel->disconnect();
|
||||
}
|
||||
|
||||
|
||||
@@ -548,8 +543,6 @@ void AutomationEditor::updateAfterPatternChange()
|
||||
m_cubicHermiteButton->setChecked( true );
|
||||
}
|
||||
|
||||
m_tensionModel.setValue( m_tensionModel.findText(
|
||||
m_pattern->getTension() ) );
|
||||
m_minLevel = m_pattern->firstObject()->minValue<float>();
|
||||
m_maxLevel = m_pattern->firstObject()->maxValue<float>();
|
||||
m_step = m_pattern->firstObject()->step<float>();
|
||||
@@ -664,8 +657,8 @@ void AutomationEditor::keyPressEvent( QKeyEvent * _ke )
|
||||
_ke->accept();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_A:
|
||||
//TODO: m_selectButton and m_moveButton are broken.
|
||||
/*case Qt::Key_A:
|
||||
if( _ke->modifiers() & Qt::ControlModifier )
|
||||
{
|
||||
m_selectButton->setChecked( TRUE );
|
||||
@@ -673,7 +666,7 @@ void AutomationEditor::keyPressEvent( QKeyEvent * _ke )
|
||||
update();
|
||||
_ke->accept();
|
||||
}
|
||||
break;
|
||||
break;*/
|
||||
|
||||
case Qt::Key_D:
|
||||
if( _ke->modifiers() & Qt::ShiftModifier )
|
||||
@@ -690,8 +683,8 @@ void AutomationEditor::keyPressEvent( QKeyEvent * _ke )
|
||||
_ke->accept();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
//TODO: m_selectButton and m_moveButton are broken.
|
||||
/*case Qt::Key_S:
|
||||
if( _ke->modifiers() & Qt::ShiftModifier )
|
||||
{
|
||||
m_selectButton->setChecked( TRUE );
|
||||
@@ -705,7 +698,7 @@ void AutomationEditor::keyPressEvent( QKeyEvent * _ke )
|
||||
m_moveButton->setChecked( TRUE );
|
||||
_ke->accept();
|
||||
}
|
||||
break;
|
||||
break;*/
|
||||
|
||||
case Qt::Key_Delete:
|
||||
deleteSelectedValues();
|
||||
@@ -800,14 +793,9 @@ void AutomationEditor::drawLine( int _x0, float _y0, int _x1, float _y1 )
|
||||
|
||||
|
||||
|
||||
void AutomationEditor::disableTensionComboBox()
|
||||
void AutomationEditor::disableTensionKnob()
|
||||
{
|
||||
m_tensionComboBox->setEnabled( false );
|
||||
m_tensionComboBox->setModel( &m_tensionDisabledModel );
|
||||
m_tensionComboBox->setToolTip(
|
||||
tr( "Choose Cubic Hermite progression to enable" ) );
|
||||
m_tensionComboBox->setWhatsThis(
|
||||
tr( "Choose Cubic Hermite progression to enable" ) );
|
||||
m_tensionKnob->setEnabled( false );
|
||||
}
|
||||
|
||||
|
||||
@@ -884,7 +872,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent * _me )
|
||||
MidiTime value_pos( pos_ticks );
|
||||
|
||||
MidiTime new_time =
|
||||
m_pattern->putValue( value_pos,
|
||||
m_pattern->setDragValue( value_pos,
|
||||
level );
|
||||
|
||||
// reset it so that it can be used for
|
||||
@@ -916,6 +904,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent * _me )
|
||||
m_pattern->removeValue( it.key() );
|
||||
engine::getSong()->setModified();
|
||||
}
|
||||
m_action = NONE;
|
||||
}
|
||||
else if( _me->button() == Qt::LeftButton &&
|
||||
m_editMode == SELECT )
|
||||
@@ -966,17 +955,21 @@ void AutomationEditor::mousePressEvent( QMouseEvent * _me )
|
||||
|
||||
void AutomationEditor::mouseReleaseEvent( QMouseEvent * _me )
|
||||
{
|
||||
m_action = NONE;
|
||||
|
||||
if( m_editMode == DRAW )
|
||||
{
|
||||
if( m_action == MOVE_VALUE )
|
||||
{
|
||||
m_pattern->applyDragValue();
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
m_action = NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
void AutomationEditor::mouseMoveEvent( QMouseEvent * _me )
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
@@ -1016,15 +1009,14 @@ void AutomationEditor::mouseMoveEvent( QMouseEvent * _me )
|
||||
|
||||
drawLine( m_drawLastTick, m_drawLastLevel,
|
||||
pos_ticks, level );
|
||||
|
||||
m_drawLastTick = pos_ticks;
|
||||
m_drawLastLevel = level;
|
||||
|
||||
// we moved the value so the value has to be
|
||||
// moved properly according to new starting-
|
||||
// time in the time map of pattern
|
||||
m_pattern->removeValue(
|
||||
MidiTime( pos_ticks ) );
|
||||
m_pattern->putValue( MidiTime( pos_ticks ),
|
||||
m_pattern->setDragValue( MidiTime( pos_ticks ),
|
||||
level );
|
||||
}
|
||||
|
||||
@@ -1992,7 +1984,7 @@ void AutomationEditor::discreteButtonToggled()
|
||||
if ( validPattern() )
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
disableTensionComboBox();
|
||||
disableTensionKnob();
|
||||
m_pattern->setProgressionType(
|
||||
AutomationPattern::DiscreteProgression );
|
||||
engine::getSong()->setModified();
|
||||
@@ -2008,7 +2000,7 @@ void AutomationEditor::linearButtonToggled()
|
||||
if ( validPattern() )
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
disableTensionComboBox();
|
||||
disableTensionKnob();
|
||||
m_pattern->setProgressionType(
|
||||
AutomationPattern::LinearProgression );
|
||||
engine::getSong()->setModified();
|
||||
@@ -2023,12 +2015,10 @@ void AutomationEditor::cubicHermiteButtonToggled()
|
||||
{
|
||||
if ( validPattern() )
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
m_tensionComboBox->setEnabled( true );
|
||||
m_tensionComboBox->setModel( &m_tensionModel );
|
||||
m_tensionComboBox->setToolTip(
|
||||
tr( "Tension value for spline" ) );
|
||||
m_tensionComboBox->setWhatsThis(
|
||||
m_tensionKnob->setModel( m_tensionModel );
|
||||
m_tensionKnob->setEnabled( true );
|
||||
toolTip::add( m_tensionKnob, tr( "Tension value for spline" ) );
|
||||
m_tensionKnob->setWhatsThis(
|
||||
tr( "A higher tension value may make a smoother curve "
|
||||
"but overshoot some values. A low tension "
|
||||
"value will cause the slope of the curve to "
|
||||
@@ -2045,13 +2035,12 @@ void AutomationEditor::cubicHermiteButtonToggled()
|
||||
|
||||
void AutomationEditor::tensionChanged()
|
||||
{
|
||||
m_pattern->setTension( m_tensionModel.currentText() );
|
||||
m_pattern->setTension( QString::number( m_tensionModel->value() ) );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AutomationEditor::selectAll()
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
|
||||
Reference in New Issue
Block a user