mirror of https://github.com/AxioDL/amuse.git
Finish CurveEditor implementation
This commit is contained in:
parent
c2a242022a
commit
2abed18784
|
@ -30,6 +30,9 @@ ProjectModel::INode* ADSRView::currentNode() const
|
||||||
|
|
||||||
void ADSRView::paintEvent(QPaintEvent* ev)
|
void ADSRView::paintEvent(QPaintEvent* ev)
|
||||||
{
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
painter.setRenderHint(QPainter::Antialiasing);
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
@ -232,17 +235,17 @@ void ADSRView::mouseMoveEvent(QMouseEvent* ev)
|
||||||
{
|
{
|
||||||
qreal newAttack = std::max(0.0, (ev->localPos().x() - 30.0) / (width() - 30.0) * totalTime);
|
qreal newAttack = std::max(0.0, (ev->localPos().x() - 30.0) / (width() - 30.0) * totalTime);
|
||||||
qreal delta = newAttack - aTime;
|
qreal delta = newAttack - aTime;
|
||||||
ctrls->setAttackAndDecay(newAttack, ctrls->m_decay->value() - delta);
|
ctrls->setAttackAndDecay(newAttack, std::max(0.0, ctrls->m_decay->value() - delta));
|
||||||
}
|
}
|
||||||
else if (m_dragPoint == 1)
|
else if (m_dragPoint == 1)
|
||||||
{
|
{
|
||||||
qreal newDecay = (ev->localPos().x() - 30.0) * totalTime / (width() - 30.0) - aTime;
|
qreal newDecay = std::max(0.0, (ev->localPos().x() - 30.0) * totalTime / (width() - 30.0) - aTime);
|
||||||
qreal newSustain = (-ev->localPos().y() + (height() - 16.0)) / (height() - 16.0);
|
qreal newSustain = (-ev->localPos().y() + (height() - 16.0)) / (height() - 16.0);
|
||||||
ctrls->setDecayAndSustain(newDecay, newSustain * 100.0);
|
ctrls->setDecayAndSustain(newDecay, newSustain * 100.0);
|
||||||
}
|
}
|
||||||
else if (m_dragPoint == 2)
|
else if (m_dragPoint == 2)
|
||||||
{
|
{
|
||||||
qreal newRelease = (width() - 30.0) * (adTime + 1.0) / (ev->localPos().x() - 30.0) - (adTime + 1.0);
|
qreal newRelease = std::max(0.0, (width() - 30.0) * (adTime + 1.0) / (ev->localPos().x() - 30.0) - (adTime + 1.0));
|
||||||
ctrls->m_release->setValue(newRelease);
|
ctrls->m_release->setValue(newRelease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -961,6 +964,7 @@ ADSRControls::ADSRControls(QWidget* parent)
|
||||||
QGridLayout* leftLayout = new QGridLayout;
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
|
||||||
QPalette palette = QWidget::palette();
|
QPalette palette = QWidget::palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
|
||||||
palette.setColor(QPalette::Text, Red);
|
palette.setColor(QPalette::Text, Red);
|
||||||
QLabel* lab = new QLabel(tr("Attack"));
|
QLabel* lab = new QLabel(tr("Attack"));
|
||||||
|
@ -990,12 +994,14 @@ ADSRControls::ADSRControls(QWidget* parent)
|
||||||
connect(m_decay, SIGNAL(valueChanged(double)), this, SLOT(decayChanged(double)));
|
connect(m_decay, SIGNAL(valueChanged(double)), this, SLOT(decayChanged(double)));
|
||||||
leftLayout->addWidget(m_decay, 1, 1);
|
leftLayout->addWidget(m_decay, 1, 1);
|
||||||
|
|
||||||
|
palette.setColor(QPalette::Text, Qt::white);
|
||||||
leftLayout->addWidget(new QLabel(tr("Sustain")), 0, 2);
|
leftLayout->addWidget(new QLabel(tr("Sustain")), 0, 2);
|
||||||
m_sustain = new QDoubleSpinBox;
|
m_sustain = new QDoubleSpinBox;
|
||||||
m_sustain->setDisabled(true);
|
m_sustain->setDisabled(true);
|
||||||
m_sustain->setRange(0.0, 100.0);
|
m_sustain->setRange(0.0, 100.0);
|
||||||
m_sustain->setDecimals(3);
|
m_sustain->setDecimals(3);
|
||||||
m_sustain->setSuffix(tr(" %"));
|
m_sustain->setSuffix(tr(" %"));
|
||||||
|
m_sustain->setPalette(palette);
|
||||||
connect(m_sustain, SIGNAL(valueChanged(double)), this, SLOT(sustainChanged(double)));
|
connect(m_sustain, SIGNAL(valueChanged(double)), this, SLOT(sustainChanged(double)));
|
||||||
leftLayout->addWidget(m_sustain, 1, 2);
|
leftLayout->addWidget(m_sustain, 1, 2);
|
||||||
|
|
||||||
|
@ -1013,10 +1019,9 @@ ADSRControls::ADSRControls(QWidget* parent)
|
||||||
connect(m_release, SIGNAL(valueChanged(double)), this, SLOT(releaseChanged(double)));
|
connect(m_release, SIGNAL(valueChanged(double)), this, SLOT(releaseChanged(double)));
|
||||||
leftLayout->addWidget(m_release, 1, 3);
|
leftLayout->addWidget(m_release, 1, 3);
|
||||||
|
|
||||||
|
palette.setColor(QPalette::Text, Qt::white);
|
||||||
leftLayout->addWidget(new QLabel(tr("DLS")), 0, 4);
|
leftLayout->addWidget(new QLabel(tr("DLS")), 0, 4);
|
||||||
m_dls = new QCheckBox;
|
m_dls = new QCheckBox;
|
||||||
palette = m_dls->palette();
|
|
||||||
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
|
||||||
m_dls->setPalette(palette);
|
m_dls->setPalette(palette);
|
||||||
m_dls->setDisabled(true);
|
m_dls->setDisabled(true);
|
||||||
m_dls->setChecked(false);
|
m_dls->setChecked(false);
|
||||||
|
@ -1031,6 +1036,7 @@ ADSRControls::ADSRControls(QWidget* parent)
|
||||||
m_velToAttack->setRange(0.0, 9999.999);
|
m_velToAttack->setRange(0.0, 9999.999);
|
||||||
m_velToAttack->setDecimals(3);
|
m_velToAttack->setDecimals(3);
|
||||||
m_velToAttack->setSingleStep(1.0);
|
m_velToAttack->setSingleStep(1.0);
|
||||||
|
m_velToAttack->setPalette(palette);
|
||||||
connect(m_velToAttack, SIGNAL(valueChanged(double)), this, SLOT(velToAttackChanged(double)));
|
connect(m_velToAttack, SIGNAL(valueChanged(double)), this, SLOT(velToAttackChanged(double)));
|
||||||
leftLayout->addWidget(m_velToAttack, 1, 5);
|
leftLayout->addWidget(m_velToAttack, 1, 5);
|
||||||
|
|
||||||
|
@ -1042,6 +1048,7 @@ ADSRControls::ADSRControls(QWidget* parent)
|
||||||
m_keyToDecay->setRange(0.0, 9999.999);
|
m_keyToDecay->setRange(0.0, 9999.999);
|
||||||
m_keyToDecay->setDecimals(3);
|
m_keyToDecay->setDecimals(3);
|
||||||
m_keyToDecay->setSingleStep(1.0);
|
m_keyToDecay->setSingleStep(1.0);
|
||||||
|
m_keyToDecay->setPalette(palette);
|
||||||
connect(m_keyToDecay, SIGNAL(valueChanged(double)), this, SLOT(keyToDecayChanged(double)));
|
connect(m_keyToDecay, SIGNAL(valueChanged(double)), this, SLOT(keyToDecayChanged(double)));
|
||||||
leftLayout->addWidget(m_keyToDecay, 1, 6);
|
leftLayout->addWidget(m_keyToDecay, 1, 6);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ find_package(Qt5Widgets)
|
||||||
find_package(Qt5Network)
|
find_package(Qt5Network)
|
||||||
find_package(Qt5Xml)
|
find_package(Qt5Xml)
|
||||||
find_package(Qt5Svg)
|
find_package(Qt5Svg)
|
||||||
|
find_package(Qt5Script)
|
||||||
find_package(Qt5LinguistTools)
|
find_package(Qt5LinguistTools)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -80,4 +81,5 @@ target_link_libraries(amuse-gui ${PLAT_LIBS}
|
||||||
${Qt5Network_LIBRARIES}
|
${Qt5Network_LIBRARIES}
|
||||||
${Qt5Xml_LIBRARIES}
|
${Qt5Xml_LIBRARIES}
|
||||||
${Qt5Svg_LIBRARIES}
|
${Qt5Svg_LIBRARIES}
|
||||||
|
${Qt5Script_LIBRARIES}
|
||||||
amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB})
|
amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
|
@ -1,12 +1,327 @@
|
||||||
#include "CurveEditor.hpp"
|
#include "CurveEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QScriptValueIterator>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
class CurveEditUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
uint8_t m_redoData[128];
|
||||||
|
uint8_t m_undoData[128];
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
CurveEditUndoCommand(const uint8_t* redoData, amuse::ObjToken<ProjectModel::CurveNode> node)
|
||||||
|
: EditorUndoCommand(node.get(), CurveControls::tr("Edit Curve"))
|
||||||
|
{
|
||||||
|
std::memcpy(m_redoData, redoData, 128);
|
||||||
|
}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
amuse::ITable& table = **m_node.cast<ProjectModel::CurveNode>()->m_obj;
|
||||||
|
if (table.Isa() == amuse::ITable::Type::Curve)
|
||||||
|
{
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
curve.data.resize(128);
|
||||||
|
std::memcpy(curve.data.data(), m_undoData, 128);
|
||||||
|
}
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
amuse::ITable& table = **m_node.cast<ProjectModel::CurveNode>()->m_obj;
|
||||||
|
if (table.Isa() == amuse::ITable::Type::Curve)
|
||||||
|
{
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
curve.data.resize(128);
|
||||||
|
std::memcpy(m_undoData, curve.data.data(), 128);
|
||||||
|
std::memcpy(curve.data.data(), m_redoData, 128);
|
||||||
|
}
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
bool mergeWith(const QUndoCommand* other)
|
||||||
|
{
|
||||||
|
if (other->id() == id())
|
||||||
|
{
|
||||||
|
std::memcpy(m_redoData, static_cast<const CurveEditUndoCommand*>(other)->m_redoData, 128);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int id() const { return int(Id::CurveEdit); }
|
||||||
|
};
|
||||||
|
|
||||||
|
CurveEditor* CurveView::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<CurveEditor*>(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::loadData(ProjectModel::CurveNode* node)
|
||||||
|
{
|
||||||
|
m_node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::unloadData()
|
||||||
|
{
|
||||||
|
m_node.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* CurveView::currentNode() const
|
||||||
|
{
|
||||||
|
return m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::paintEvent(QPaintEvent* ev)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
amuse::ITable& table = **m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
qreal deviceRatio = devicePixelRatioF();
|
||||||
|
qreal penWidth = std::max(std::floor(deviceRatio), 1.0) / deviceRatio;
|
||||||
|
|
||||||
|
painter.setPen(QPen(QColor(127, 127, 127), penWidth));
|
||||||
|
painter.setFont(m_gridFont);
|
||||||
|
qreal yIncrement = (height() - 16.0) / 10.0;
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
qreal thisY = i * yIncrement;
|
||||||
|
qreal textY = thisY - (i == 0 ? 2.0 : (i == 10 ? 16.0 : 8.0));
|
||||||
|
painter.drawStaticText(QPointF(0.0, textY), m_percentTexts[i]);
|
||||||
|
painter.drawLine(QPointF(30.0, thisY), QPointF(width(), thisY));
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal xIncrement = (width() - 30.0) / 10.0;
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
qreal thisX = i * xIncrement + 30.0;
|
||||||
|
qreal textX = thisX - (i == 10 ? 30.0 : 15.0);
|
||||||
|
painter.drawStaticText(QPointF(textX, height() - 16.0), m_percentTextsCenter[i]);
|
||||||
|
painter.drawLine(QPointF(thisX, 0.0), QPointF(thisX, height() - 16.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
xIncrement = (width() - 30.0) / 127.0;
|
||||||
|
QPointF lastPt;
|
||||||
|
painter.setPen(QPen(Qt::white, penWidth * 3.0));
|
||||||
|
for (i = 0; i < curve.data.size(); ++i)
|
||||||
|
{
|
||||||
|
QPointF thisPt(i * xIncrement + 30.0, (height() - 16.0) - (height() - 16.0) * (curve.data[i] / 127.0));
|
||||||
|
if (i)
|
||||||
|
painter.drawLine(lastPt, thisPt);
|
||||||
|
lastPt = thisPt;
|
||||||
|
}
|
||||||
|
for (; i < 128; ++i)
|
||||||
|
{
|
||||||
|
QPointF thisPt(i * xIncrement + 30.0, height() - 16.0);
|
||||||
|
if (i)
|
||||||
|
painter.drawLine(lastPt, thisPt);
|
||||||
|
lastPt = thisPt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveView::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
CurveView* view = getEditor()->m_curveView;
|
||||||
|
amuse::ITable& table = **view->m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
qreal xIncrement = (width() - 30.0) / 127.0;
|
||||||
|
int idx = int(std::round((ev->localPos().x() - 30.0) / xIncrement));
|
||||||
|
if (idx < 0 || idx > 127)
|
||||||
|
return;
|
||||||
|
int val = 127 - amuse::clamp(0, int(std::round(ev->localPos().y() / (height() - 16.0) * 127.0)), 127);
|
||||||
|
|
||||||
|
curve.data.resize(128);
|
||||||
|
uint8_t newData[128];
|
||||||
|
std::memcpy(newData, curve.data.data(), 128);
|
||||||
|
newData[idx] = uint8_t(val);
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new CurveEditUndoCommand(newData, m_node));
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveView::CurveView(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 11; ++i)
|
||||||
|
{
|
||||||
|
m_percentTexts[i].setText(QStringLiteral("%1%").arg(100 - i * 10));
|
||||||
|
m_percentTexts[i].setTextOption(QTextOption(Qt::AlignVCenter | Qt::AlignRight));
|
||||||
|
m_percentTexts[i].setTextWidth(28.0);
|
||||||
|
m_percentTextsCenter[i].setText(QStringLiteral("%1%").arg(i * 10));
|
||||||
|
m_percentTextsCenter[i].setTextOption(QTextOption(Qt::AlignBaseline | Qt::AlignCenter));
|
||||||
|
m_percentTextsCenter[i].setTextWidth(28.0);
|
||||||
|
}
|
||||||
|
m_gridFont.setPointSize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveEditor* CurveControls::getEditor() const
|
||||||
|
{
|
||||||
|
return qobject_cast<CurveEditor*>(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::loadData()
|
||||||
|
{
|
||||||
|
m_lineEdit->setDisabled(false);
|
||||||
|
m_setExpr->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::unloadData()
|
||||||
|
{
|
||||||
|
m_lineEdit->setDisabled(true);
|
||||||
|
m_setExpr->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::exprCommit()
|
||||||
|
{
|
||||||
|
CurveView* view = getEditor()->m_curveView;
|
||||||
|
amuse::ITable& table = **view->m_node->m_obj;
|
||||||
|
if (table.Isa() != amuse::ITable::Type::Curve)
|
||||||
|
return;
|
||||||
|
amuse::Curve& curve = static_cast<amuse::Curve&>(table);
|
||||||
|
|
||||||
|
QScriptSyntaxCheckResult res = QScriptEngine::checkSyntax(m_lineEdit->text());
|
||||||
|
if (res.state() != QScriptSyntaxCheckResult::Valid)
|
||||||
|
{
|
||||||
|
m_errLabel->setText(res.errorMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_errLabel->setText(QString());
|
||||||
|
|
||||||
|
curve.data.resize(128);
|
||||||
|
uint8_t newData[128];
|
||||||
|
std::memcpy(newData, curve.data.data(), 128);
|
||||||
|
QScriptProgram prog(m_lineEdit->text());
|
||||||
|
bool notANumber = false;
|
||||||
|
for (int i = 0; i < 128; ++i)
|
||||||
|
{
|
||||||
|
m_engine.globalObject().setProperty(QStringLiteral("x"), i / 127.0);
|
||||||
|
QScriptValue val = m_engine.evaluate(prog);
|
||||||
|
if (val.isNumber())
|
||||||
|
{
|
||||||
|
newData[i] = uint8_t(amuse::clamp(0, int(std::round(val.toNumber() * 127.0)), 127));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notANumber = true;
|
||||||
|
newData[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notANumber)
|
||||||
|
m_errLabel->setText(tr("Did not evaluate as a number"));
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new CurveEditUndoCommand(newData, view->m_node));
|
||||||
|
view->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveControls::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_errLabel->setGeometry(22, 78, width() - 44, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveControls::CurveControls(QWidget* parent)
|
||||||
|
: QFrame(parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
setFixedHeight(100);
|
||||||
|
setFrameShape(QFrame::StyledPanel);
|
||||||
|
setFrameShadow(QFrame::Sunken);
|
||||||
|
setBackgroundRole(QPalette::Base);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
|
||||||
|
leftLayout->addWidget(new QLabel(tr("Expression")), 0, 0);
|
||||||
|
m_lineEdit = new QLineEdit;
|
||||||
|
m_lineEdit->setDisabled(true);
|
||||||
|
QPalette palette = m_lineEdit->palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
m_lineEdit->setPalette(palette);
|
||||||
|
connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(exprCommit()));
|
||||||
|
leftLayout->addWidget(m_lineEdit, 1, 0);
|
||||||
|
|
||||||
|
m_setExpr = new QPushButton(tr("Apply"));
|
||||||
|
m_setExpr->setDisabled(true);
|
||||||
|
connect(m_setExpr, SIGNAL(clicked(bool)), this, SLOT(exprCommit()));
|
||||||
|
leftLayout->addWidget(m_setExpr, 1, 1);
|
||||||
|
|
||||||
|
m_errLabel = new QLabel(this);
|
||||||
|
QFont font = m_errLabel->font();
|
||||||
|
font.setPointSize(8);
|
||||||
|
m_errLabel->setFont(font);
|
||||||
|
palette.setColor(QPalette::Text, Qt::red);
|
||||||
|
m_errLabel->setPalette(palette);
|
||||||
|
|
||||||
|
leftLayout->setColumnMinimumWidth(0, 500);
|
||||||
|
leftLayout->setColumnStretch(0, 1);
|
||||||
|
leftLayout->setColumnMinimumWidth(1, 75);
|
||||||
|
leftLayout->setColumnStretch(1, 0);
|
||||||
|
leftLayout->setRowMinimumHeight(0, 22);
|
||||||
|
leftLayout->setRowMinimumHeight(1, 37);
|
||||||
|
leftLayout->setContentsMargins(10, 6, 10, 14);
|
||||||
|
|
||||||
|
mainLayout->addLayout(leftLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
QScriptValueIterator it(m_engine.globalObject().property(QStringLiteral("Math")));
|
||||||
|
QString docStr = tr("Expression interpreter mapping x:[0,1] to y:[0,1] with the following constants and functions available:\n");
|
||||||
|
bool needsComma = false;
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
m_engine.globalObject().setProperty(it.name(), it.value());
|
||||||
|
if (needsComma)
|
||||||
|
docStr += QStringLiteral(", ");
|
||||||
|
needsComma = true;
|
||||||
|
docStr += it.name();
|
||||||
|
}
|
||||||
|
m_lineEdit->setToolTip(docStr);
|
||||||
|
}
|
||||||
|
|
||||||
bool CurveEditor::loadData(ProjectModel::CurveNode* node)
|
bool CurveEditor::loadData(ProjectModel::CurveNode* node)
|
||||||
{
|
{
|
||||||
return false;
|
m_curveView->loadData(node);
|
||||||
|
m_controls->loadData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CurveEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_curveView->unloadData();
|
||||||
|
m_controls->unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* CurveEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_curveView->currentNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
CurveEditor::CurveEditor(QWidget* parent)
|
CurveEditor::CurveEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent), m_curveView(new CurveView), m_controls(new CurveControls)
|
||||||
{
|
{
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(1);
|
||||||
|
layout->addWidget(m_curveView);
|
||||||
|
layout->addWidget(m_controls);
|
||||||
|
setLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,65 @@
|
||||||
#define AMUSE_CURVE_EDITOR_HPP
|
#define AMUSE_CURVE_EDITOR_HPP
|
||||||
|
|
||||||
#include "EditorWidget.hpp"
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QStaticText>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QScriptEngine>
|
||||||
|
|
||||||
|
class CurveEditor;
|
||||||
|
|
||||||
|
class CurveView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CurveControls;
|
||||||
|
amuse::ObjToken<ProjectModel::CurveNode> m_node;
|
||||||
|
QFont m_gridFont;
|
||||||
|
QStaticText m_percentTexts[11];
|
||||||
|
QStaticText m_percentTextsCenter[11];
|
||||||
|
CurveEditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit CurveView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::CurveNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* ev);
|
||||||
|
void mousePressEvent(QMouseEvent* ev);
|
||||||
|
void mouseMoveEvent(QMouseEvent* ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurveControls : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class CurveView;
|
||||||
|
QLineEdit* m_lineEdit;
|
||||||
|
QLabel* m_errLabel;
|
||||||
|
QPushButton* m_setExpr;
|
||||||
|
QScriptEngine m_engine;
|
||||||
|
CurveEditor* getEditor() const;
|
||||||
|
public:
|
||||||
|
explicit CurveControls(QWidget* parent = Q_NULLPTR);
|
||||||
|
void loadData();
|
||||||
|
void unloadData();
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
public slots:
|
||||||
|
void exprCommit();
|
||||||
|
};
|
||||||
|
|
||||||
class CurveEditor : public EditorWidget
|
class CurveEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
friend class CurveView;
|
||||||
|
friend class CurveControls;
|
||||||
|
CurveView* m_curveView;
|
||||||
|
CurveControls* m_controls;
|
||||||
public:
|
public:
|
||||||
explicit CurveEditor(QWidget* parent = Q_NULLPTR);
|
explicit CurveEditor(QWidget* parent = Q_NULLPTR);
|
||||||
bool loadData(ProjectModel::CurveNode* node);
|
bool loadData(ProjectModel::CurveNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //AMUSE_CURVE_EDITOR_HPP
|
#endif //AMUSE_CURVE_EDITOR_HPP
|
||||||
|
|
|
@ -33,7 +33,8 @@ protected:
|
||||||
ADSRRelease,
|
ADSRRelease,
|
||||||
ADSRDLS,
|
ADSRDLS,
|
||||||
ADSRVelToAttack,
|
ADSRVelToAttack,
|
||||||
ADSRKeyToDecay
|
ADSRKeyToDecay,
|
||||||
|
CurveEdit
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
EditorUndoCommand(amuse::ObjToken<ProjectModel::INode> node,
|
EditorUndoCommand(amuse::ObjToken<ProjectModel::INode> node,
|
||||||
|
|
|
@ -764,6 +764,9 @@ SampleControls::SampleControls(QWidget* parent)
|
||||||
setBackgroundRole(QPalette::Base);
|
setBackgroundRole(QPalette::Base);
|
||||||
setAutoFillBackground(true);
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
QPalette palette = QWidget::palette();
|
||||||
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
|
|
||||||
QHBoxLayout* mainLayout = new QHBoxLayout;
|
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
QGridLayout* leftLayout = new QGridLayout;
|
QGridLayout* leftLayout = new QGridLayout;
|
||||||
|
@ -777,8 +780,6 @@ SampleControls::SampleControls(QWidget* parent)
|
||||||
|
|
||||||
leftLayout->addWidget(new QLabel(tr("Loop")), 0, 1);
|
leftLayout->addWidget(new QLabel(tr("Loop")), 0, 1);
|
||||||
m_loopCheck = new QCheckBox;
|
m_loopCheck = new QCheckBox;
|
||||||
QPalette palette = m_loopCheck->palette();
|
|
||||||
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
|
||||||
m_loopCheck->setPalette(palette);
|
m_loopCheck->setPalette(palette);
|
||||||
m_loopCheck->setDisabled(true);
|
m_loopCheck->setDisabled(true);
|
||||||
connect(m_loopCheck, SIGNAL(stateChanged(int)), this, SLOT(loopStateChanged(int)));
|
connect(m_loopCheck, SIGNAL(stateChanged(int)), this, SLOT(loopStateChanged(int)));
|
||||||
|
@ -786,18 +787,21 @@ SampleControls::SampleControls(QWidget* parent)
|
||||||
|
|
||||||
leftLayout->addWidget(new QLabel(tr("Start")), 0, 2);
|
leftLayout->addWidget(new QLabel(tr("Start")), 0, 2);
|
||||||
m_loopStart = new QSpinBox;
|
m_loopStart = new QSpinBox;
|
||||||
|
m_loopStart->setPalette(palette);
|
||||||
m_loopStart->setDisabled(true);
|
m_loopStart->setDisabled(true);
|
||||||
connect(m_loopStart, SIGNAL(valueChanged(int)), this, SLOT(startValueChanged(int)));
|
connect(m_loopStart, SIGNAL(valueChanged(int)), this, SLOT(startValueChanged(int)));
|
||||||
leftLayout->addWidget(m_loopStart, 1, 2);
|
leftLayout->addWidget(m_loopStart, 1, 2);
|
||||||
|
|
||||||
leftLayout->addWidget(new QLabel(tr("End")), 0, 3);
|
leftLayout->addWidget(new QLabel(tr("End")), 0, 3);
|
||||||
m_loopEnd = new QSpinBox;
|
m_loopEnd = new QSpinBox;
|
||||||
|
m_loopEnd->setPalette(palette);
|
||||||
m_loopEnd->setDisabled(true);
|
m_loopEnd->setDisabled(true);
|
||||||
connect(m_loopEnd, SIGNAL(valueChanged(int)), this, SLOT(endValueChanged(int)));
|
connect(m_loopEnd, SIGNAL(valueChanged(int)), this, SLOT(endValueChanged(int)));
|
||||||
leftLayout->addWidget(m_loopEnd, 1, 3);
|
leftLayout->addWidget(m_loopEnd, 1, 3);
|
||||||
|
|
||||||
leftLayout->addWidget(new QLabel(tr("Base Pitch")), 0, 4);
|
leftLayout->addWidget(new QLabel(tr("Base Pitch")), 0, 4);
|
||||||
m_basePitch = new QSpinBox;
|
m_basePitch = new QSpinBox;
|
||||||
|
m_basePitch->setPalette(palette);
|
||||||
m_basePitch->setDisabled(true);
|
m_basePitch->setDisabled(true);
|
||||||
m_basePitch->setMinimum(0);
|
m_basePitch->setMinimum(0);
|
||||||
m_basePitch->setMaximum(127);
|
m_basePitch->setMaximum(127);
|
||||||
|
|
|
@ -4,94 +4,94 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ADSRControls</name>
|
<name>ADSRControls</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="332"/>
|
<location filename="../ADSREditor.cpp" line="335"/>
|
||||||
<source>Change Attack</source>
|
<source>Change Attack</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="396"/>
|
<location filename="../ADSREditor.cpp" line="399"/>
|
||||||
<source>Change Decay</source>
|
<source>Change Decay</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="460"/>
|
<location filename="../ADSREditor.cpp" line="463"/>
|
||||||
<source>Change Sustain</source>
|
<source>Change Sustain</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="525"/>
|
<location filename="../ADSREditor.cpp" line="528"/>
|
||||||
<source>Change Attack/Decay</source>
|
<source>Change Attack/Decay</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="599"/>
|
<location filename="../ADSREditor.cpp" line="602"/>
|
||||||
<source>Change Decay/Sustain</source>
|
<source>Change Decay/Sustain</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="672"/>
|
<location filename="../ADSREditor.cpp" line="675"/>
|
||||||
<source>Change Release</source>
|
<source>Change Release</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="762"/>
|
<location filename="../ADSREditor.cpp" line="765"/>
|
||||||
<source>Change DLS</source>
|
<source>Change DLS</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="849"/>
|
<location filename="../ADSREditor.cpp" line="852"/>
|
||||||
<source>Change Vel To Attack</source>
|
<source>Change Vel To Attack</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="902"/>
|
<location filename="../ADSREditor.cpp" line="905"/>
|
||||||
<source>Change Key To Decay</source>
|
<source>Change Key To Decay</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="966"/>
|
<location filename="../ADSREditor.cpp" line="970"/>
|
||||||
<source>Attack</source>
|
<source>Attack</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="974"/>
|
<location filename="../ADSREditor.cpp" line="978"/>
|
||||||
<location filename="../ADSREditor.cpp" line="988"/>
|
<location filename="../ADSREditor.cpp" line="992"/>
|
||||||
<location filename="../ADSREditor.cpp" line="1011"/>
|
<location filename="../ADSREditor.cpp" line="1017"/>
|
||||||
<source> sec</source>
|
<source> sec</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="980"/>
|
<location filename="../ADSREditor.cpp" line="984"/>
|
||||||
<source>Decay</source>
|
<source>Decay</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="993"/>
|
<location filename="../ADSREditor.cpp" line="998"/>
|
||||||
<source>Sustain</source>
|
<source>Sustain</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="998"/>
|
<location filename="../ADSREditor.cpp" line="1003"/>
|
||||||
<source> %</source>
|
<source> %</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="1003"/>
|
<location filename="../ADSREditor.cpp" line="1009"/>
|
||||||
<source>Release</source>
|
<source>Release</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="1016"/>
|
<location filename="../ADSREditor.cpp" line="1023"/>
|
||||||
<source>DLS</source>
|
<source>DLS</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="1026"/>
|
<location filename="../ADSREditor.cpp" line="1031"/>
|
||||||
<source>Vel To Attack</source>
|
<source>Vel To Attack</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ADSREditor.cpp" line="1037"/>
|
<location filename="../ADSREditor.cpp" line="1043"/>
|
||||||
<source>Key To Decay</source>
|
<source>Key To Decay</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -104,6 +104,35 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>CurveControls</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../CurveEditor.cpp" line="16"/>
|
||||||
|
<source>Edit Curve</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../CurveEditor.cpp" line="228"/>
|
||||||
|
<source>Did not evaluate as a number</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../CurveEditor.cpp" line="253"/>
|
||||||
|
<source>Expression</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../CurveEditor.cpp" line="262"/>
|
||||||
|
<source>Apply</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../CurveEditor.cpp" line="286"/>
|
||||||
|
<source>Expression interpreter mapping x:[0,1] to y:[0,1] with the following constants and functions available:
|
||||||
|
</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow</name>
|
<name>MainWindow</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -554,7 +583,7 @@
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="507"/>
|
<location filename="../SampleEditor.cpp" line="507"/>
|
||||||
<location filename="../SampleEditor.cpp" line="522"/>
|
<location filename="../SampleEditor.cpp" line="522"/>
|
||||||
<location filename="../SampleEditor.cpp" line="778"/>
|
<location filename="../SampleEditor.cpp" line="781"/>
|
||||||
<source>Loop</source>
|
<source>Loop</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -590,27 +619,27 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="752"/>
|
<location filename="../SampleEditor.cpp" line="752"/>
|
||||||
<location filename="../SampleEditor.cpp" line="818"/>
|
<location filename="../SampleEditor.cpp" line="822"/>
|
||||||
<source>Nothing Loaded</source>
|
<source>Nothing Loaded</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="771"/>
|
<location filename="../SampleEditor.cpp" line="774"/>
|
||||||
<source>Zoom</source>
|
<source>Zoom</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="787"/>
|
<location filename="../SampleEditor.cpp" line="788"/>
|
||||||
<source>Start</source>
|
<source>Start</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="793"/>
|
<location filename="../SampleEditor.cpp" line="795"/>
|
||||||
<source>End</source>
|
<source>End</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SampleEditor.cpp" line="799"/>
|
<location filename="../SampleEditor.cpp" line="802"/>
|
||||||
<source>Base Pitch</source>
|
<source>Base Pitch</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -715,9 +715,9 @@ bool SoundMacro::CmdScaleVolume::Do(SoundMacroState& st, Voice& vox) const
|
||||||
if (table.id != 0)
|
if (table.id != 0)
|
||||||
{
|
{
|
||||||
const Curve* curveData = vox.getAudioGroup().getPool().tableAsCurves(table.id);
|
const Curve* curveData = vox.getAudioGroup().getPool().tableAsCurves(table.id);
|
||||||
if (curveData)
|
if (curveData && curveData->data.size() >= 128)
|
||||||
{
|
{
|
||||||
vox.m_curVol = curveData->data.at(eval) / 127.f;
|
vox.m_curVol = curveData->data[eval] / 127.f;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue