/* * Olive Community Edition - Non-Linear Video Editor * Copyright (C) 2025 Olive CE Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ // Copyright OpenFX and contributors to the OpenFX project. #ifndef PARAM_INSTANCE_H #define PARAM_INSTANCE_H #include #include #include #include #include "ofxhParam.h" #include "node/nodeundo.h" #include "node/plugins/Plugin.h" #include "core.h" #include "undo/undocommand.h" namespace olive { namespace plugin { inline QString ParamChangeLabel(const OFX::Host::Param::Descriptor &descriptor) { return QStringLiteral("Change %1") .arg(QString::fromStdString(descriptor.getName())); } void SubmitUndoCommand(const std::shared_ptr &node, UndoCommand *command, const QString &label); class PushbuttonInstance : public OFX::Host::Param::PushbuttonInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor *_descriptor; public: PushbuttonInstance(std::shared_ptr effect, const std::string &name, OFX::Host::Param::Descriptor &descriptor) : OFX::Host::Param::PushbuttonInstance(descriptor) , node(effect) { _descriptor = &descriptor; }; }; class IntegerInstance : public OFX::Host::Param::IntegerInstance { protected: std::shared_ptr _node; OFX::Host::Param::Descriptor& _descriptor; QString id; public: IntegerInstance(std::shared_ptrnode, OFX::Host::Param::Descriptor &descriptor) : _node(node), _descriptor(descriptor), OFX::Host::Param::IntegerInstance(_descriptor){} OfxStatus get(int &a) { if (id.isEmpty()) { return kOfxStatErrBadHandle; } QVariant variant=_node->GetStandardValue(id); if (variant.typeId()==QVariant::Int) { a=variant.toInt(); return kOfxStatOK; } a=0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, int &data) { if (id.isEmpty()) { return kOfxStatErrBadHandle; } QVariant variant=_node->GetValueAtTime(id, rational::fromDouble(time)); if (variant.typeId()==QVariant::Int) { data=variant.toInt(); return kOfxStatOK; } data=0; return kOfxStatErrValue; } OfxStatus set(int data) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kInt, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(_node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); id=_descriptor.getName().c_str(); return kOfxStatOK; } OfxStatus set(OfxTime time, int data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(_node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); id=_descriptor.getName().c_str(); return kOfxStatOK; } }; class DoubleInstance : public OFX::Host::Param::DoubleInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: DoubleInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::DoubleInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(double& data) { QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toDouble(); return kOfxStatOK; } data = 0.0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, double& data) { QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toDouble(); return kOfxStatOK; } data = 0.0; return kOfxStatErrValue; } OfxStatus set(double data) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kFloat, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus derive(OfxTime, double&) { return kOfxStatErrUnsupported; } OfxStatus integrate(OfxTime, OfxTime, double&) { return kOfxStatErrUnsupported; } }; class BooleanInstance : public OFX::Host::Param::BooleanInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: BooleanInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::BooleanInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(bool& data) { QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toBool(); return kOfxStatOK; } data = false; return kOfxStatErrValue; } OfxStatus get(OfxTime time, bool& data) { QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toBool(); return kOfxStatOK; } data = false; return kOfxStatErrValue; } OfxStatus set(bool data) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kBoolean, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, bool data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class ChoiceInstance : public OFX::Host::Param::ChoiceInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: ChoiceInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::ChoiceInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(int& data) { QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toInt(); return kOfxStatOK; } data = 0; return kOfxStatErrValue; } OfxStatus get(OfxTime time, int& data) { QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toInt(); return kOfxStatOK; } data = 0; return kOfxStatErrValue; } OfxStatus set(int data) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kCombo, data); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, int data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), data, 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class RGBAInstance : public OFX::Host::Param::RGBAInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: RGBAInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::RGBAInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(double& r,double& g,double& b,double& a) { olive::core::Color c = node->GetStandardValue(_descriptor.getName().c_str()) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); a = static_cast(c.alpha()); return kOfxStatOK; } OfxStatus get(OfxTime time, double& r,double& g,double& b,double& a) { olive::core::Color c = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); a = static_cast(c.alpha()); return kOfxStatOK; } OfxStatus set(double r,double g,double b,double a) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kColor, QVariant::fromValue(olive::core::Color(r, g, b, a))); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double r,double g,double b,double a) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), r, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), g, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), b, 2, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), a, 3, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class RGBInstance : public OFX::Host::Param::RGBInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: RGBInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::RGBInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(double& r,double& g,double& b) { olive::core::Color c = node->GetStandardValue(_descriptor.getName().c_str()) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); return kOfxStatOK; } OfxStatus get(OfxTime time, double& r,double& g,double& b) { olive::core::Color c = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); r = static_cast(c.red()); g = static_cast(c.green()); b = static_cast(c.blue()); return kOfxStatOK; } OfxStatus set(double r,double g,double b) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kColor, QVariant::fromValue(olive::core::Color(r, g, b))); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, double r,double g,double b) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), r, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), g, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), b, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Double2DInstance : public OFX::Host::Param::Double2DInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: Double2DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::Double2DInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(double& x,double& y) { QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus get(OfxTime time,double& x,double& y) { QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus set(double x,double y) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec2, QVector2D(x, y)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time,double x,double y) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Integer2DInstance : public OFX::Host::Param::Integer2DInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: Integer2DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::Integer2DInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(int& x,int& y) { QVector2D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus get(OfxTime time,int& x,int& y) { QVector2D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); return kOfxStatOK; } OfxStatus set(int x,int y) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec2, QVector2D(x, y)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time,int x,int y) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Double3DInstance : public OFX::Host::Param::Double3DInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: Double3DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::Double3DInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(double& x,double& y,double& z) { QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus get(OfxTime time,double& x,double& y,double& z) { QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus set(double x,double y,double z) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec3, QVector3D(x, y, z)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time,double x,double y,double z) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), z, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class Integer3DInstance : public OFX::Host::Param::Integer3DInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: Integer3DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::Integer3DInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(int& x,int& y,int& z) { QVector3D vec = node->GetStandardValue(_descriptor.getName().c_str()) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus get(OfxTime time,int& x,int& y,int& z) { QVector3D vec = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)) .value(); x = static_cast(vec.x()); y = static_cast(vec.y()); z = static_cast(vec.z()); return kOfxStatOK; } OfxStatus set(int x,int y,int z) { SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kVec3, QVector3D(x, y, z)); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time,int x,int y,int z) { auto command = new MultiUndoCommand(); const QString name = _descriptor.getName().c_str(); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), x, 0, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), y, 1, command, true); Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), z, 2, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class StringInstance : public OFX::Host::Param::StringInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: StringInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::StringInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(std::string &data) { QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus get(OfxTime time, std::string &data) { QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus set(const char *data) { QString v = QString::fromUtf8(data); SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kText, v); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, const char *data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), QString::fromUtf8(data), 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class CustomInstance : public OFX::Host::Param::CustomInstance { protected: std::shared_ptr node; OFX::Host::Param::Descriptor& _descriptor; public: CustomInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::CustomInstance(descriptor) , node(effect) , _descriptor(descriptor) { (void)name; } OfxStatus get(std::string &data) { QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); if (variant.canConvert()) { data = variant.toByteArray().toStdString(); return kOfxStatOK; } if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus get(OfxTime time, std::string &data) { QVariant variant = node->GetValueAtTime(_descriptor.getName().c_str(), rational::fromDouble(time)); if (variant.canConvert()) { data = variant.toByteArray().toStdString(); return kOfxStatOK; } if (variant.canConvert()) { data = variant.toString().toStdString(); return kOfxStatOK; } data.clear(); return kOfxStatErrValue; } OfxStatus set(const char *data) { QByteArray v = QByteArray(data); SplitValue split = NodeValue::split_normal_value_into_track_values( NodeValue::kBinary, v); auto command = new NodeParamSetSplitStandardValueCommand( NodeInput(node.get(), _descriptor.getName().c_str()), split); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } OfxStatus set(OfxTime time, const char *data) { auto command = new MultiUndoCommand(); Node::SetValueAtTime( NodeInput(node.get(), _descriptor.getName().c_str()), rational::fromDouble(time), QByteArray(data), 0, command, true); SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); return kOfxStatOK; } }; class GroupInstance : public OFX::Host::Param::GroupInstance { public: GroupInstance(OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::GroupInstance(descriptor) { } }; class PageInstance : public OFX::Host::Param::PageInstance { public: PageInstance(OFX::Host::Param::Descriptor& descriptor) : OFX::Host::Param::PageInstance(descriptor) { } }; } } #endif // HOST_DEMO_PARAM_INSTANCE_H