Add missing param instance types (String, Double3D/Integer3D, Group/Page, Custom/Bytes) and mapping to node inputs. app/pluginSupport/OlivePluginInstance.cpp, app/node/plugins/Plugin.cpp

This commit is contained in:
2026-01-04 22:53:26 +08:00
parent 3b16824f34
commit 1b29bd147e
6 changed files with 373 additions and 9 deletions
+5
View File
@@ -32,6 +32,11 @@
- 为什么需要:插件在编辑参数、显示进度、根据时间线上下文渲染时依赖这些回调。
- 可能改动:实现 editBegin/editEnd 通知;progressStart/Update/End 与 UI 进度条连接;timelineGetTime/GotoTime/Bounds 与工程时间轴连接。
7) 持久消息展示与清理机制需要完善
- 现状:我们已在 Host/Instance 里保存消息并能弹窗,但 UI 面板还需要稳定地展示、更新和清理。
- 为什么需要:插件经常用 persistent message 提示错误或警告,需要可追踪、可清除。
- 可能改动:统一消息存储(Host/Instance),提供 UI 列表、清除按钮、计数徽标,并保证信号更新。
8) Project Extent / Fielding 行为待确认
- 现状:`OlivePluginInstance::getProjectExtent()` 有 “TODO” 注释。
- 为什么需要:OFX 插件会根据项目尺寸、扫描线场信息做渲染决策。
+46 -7
View File
@@ -49,8 +49,39 @@ olive::plugin::PluginNode::PluginNode(
{
plugin_instance_=plugin;
bool has_texture_input = false;
QHash<QString, QString> group_labels;
QHash<QString, QString> page_labels;
QHash<QString, QString> page_for_param;
auto params=plugin_instance_->getParams();
for (auto param: params) {
const std::string &ofxType = param.second->getType();
if (ofxType == kOfxParamTypeGroup) {
const QString name = QString::fromStdString(param.first);
const QString label =
QString::fromStdString(param.second->getLabel());
group_labels.insert(name, label.isEmpty() ? name : label);
} else if (ofxType == kOfxParamTypePage) {
const QString name = QString::fromStdString(param.first);
const QString label =
QString::fromStdString(param.second->getLabel());
page_labels.insert(name, label.isEmpty() ? name : label);
const auto &props = param.second->getProperties();
int count = props.getDimension(kOfxParamPropPageChild);
for (int i = 0; i < count; ++i) {
const std::string &child =
props.getStringProperty(kOfxParamPropPageChild, i);
if (child == kOfxParamPageSkipRow ||
child == kOfxParamPageSkipColumn) {
continue;
}
page_for_param.insert(QString::fromStdString(child),
page_labels.value(name));
}
}
}
for (auto param: params) {
NodeValue::Type type = NodeValue::kNone;
@@ -82,17 +113,25 @@ olive::plugin::PluginNode::PluginNode(
type = NodeValue::kBinary;
} else if (ofxType == kOfxParamTypePushButton) {
type = NodeValue::kPushButton;
} else if (ofxType == kOfxParamTypeGroup) {
// TODO
} else if (ofxType == kOfxParamTypePage) {
// TODO
} else if (ofxType == kOfxParamTypeGroup ||
ofxType == kOfxParamTypePage) {
continue;
}else {
type = NodeValue::kNone;
}
AddInput(param.second->getName().data(), type);
const QString input_id = QString::fromStdString(param.second->getName());
AddInput(input_id, type);
const QString parent =
QString::fromStdString(param.second->getParentName());
if (!parent.isEmpty()) {
SetInputProperty(input_id, QStringLiteral("ui_group"),
group_labels.value(parent, parent));
}
if (page_for_param.contains(input_id)) {
SetInputProperty(input_id, QStringLiteral("ui_page"),
page_for_param.value(input_id));
}
}
const auto &clips = plugin_instance_->getDescriptor().getClips();
+13
View File
@@ -171,6 +171,8 @@ OlivePluginInstance::newParam(const std::string &name,
return new BooleanInstance(node_, name, desc);
} else if (type == kOfxParamTypeChoice) {
return new ChoiceInstance(node_, name, desc);
} else if (type == kOfxParamTypeString) {
return new StringInstance(node_, name, desc);
} else if (type == kOfxParamTypeRGBA) {
return new RGBAInstance(node_, name, desc);
} else if (type == kOfxParamTypeRGB) {
@@ -179,6 +181,17 @@ OlivePluginInstance::newParam(const std::string &name,
return new Double2DInstance(node_, name, desc);
} else if (type == kOfxParamTypeInteger2D) {
return new Integer2DInstance(node_, name, desc);
} else if (type == kOfxParamTypeDouble3D) {
return new Double3DInstance(node_, name, desc);
} else if (type == kOfxParamTypeInteger3D) {
return new Integer3DInstance(node_, name, desc);
} else if (type == kOfxParamTypeCustom ||
type == kOfxParamTypeBytes) {
return new CustomInstance(node_, name, desc);
} else if (type == kOfxParamTypeGroup) {
return new GroupInstance(desc);
} else if (type == kOfxParamTypePage) {
return new PageInstance(desc);
} else if (type == kOfxParamTypePushButton) {
return new PushbuttonInstance(node_, name, desc);
}
+261
View File
@@ -23,6 +23,7 @@
#include <QString>
#include <QVector2D>
#include <QVector3D>
#include <QVariant>
#include "ofxhParam.h"
#include "node/nodeundo.h"
@@ -528,6 +529,266 @@ public:
return kOfxStatOK;
}
};
class Double3DInstance : public OFX::Host::Param::Double3DInstance {
protected:
std::shared_ptr<PluginNode> node;
OFX::Host::Param::Descriptor& _descriptor;
public:
Double3DInstance(std::shared_ptr<PluginNode> 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<QVector3D>();
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
z = static_cast<double>(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<QVector3D>();
x = static_cast<double>(vec.x());
y = static_cast<double>(vec.y());
z = static_cast<double>(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);
Core::instance()->undo_stack()->push(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);
Core::instance()->undo_stack()->push(command,
ParamChangeLabel(_descriptor));
return kOfxStatOK;
}
};
class Integer3DInstance : public OFX::Host::Param::Integer3DInstance {
protected:
std::shared_ptr<PluginNode> node;
OFX::Host::Param::Descriptor& _descriptor;
public:
Integer3DInstance(std::shared_ptr<PluginNode> 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<QVector3D>();
x = static_cast<int>(vec.x());
y = static_cast<int>(vec.y());
z = static_cast<int>(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<QVector3D>();
x = static_cast<int>(vec.x());
y = static_cast<int>(vec.y());
z = static_cast<int>(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);
Core::instance()->undo_stack()->push(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);
Core::instance()->undo_stack()->push(command,
ParamChangeLabel(_descriptor));
return kOfxStatOK;
}
};
class StringInstance : public OFX::Host::Param::StringInstance {
protected:
std::shared_ptr<PluginNode> node;
OFX::Host::Param::Descriptor& _descriptor;
public:
StringInstance(std::shared_ptr<PluginNode> 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<QString>()) {
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<QString>()) {
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);
Core::instance()->undo_stack()->push(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);
Core::instance()->undo_stack()->push(command,
ParamChangeLabel(_descriptor));
return kOfxStatOK;
}
};
class CustomInstance : public OFX::Host::Param::CustomInstance {
protected:
std::shared_ptr<PluginNode> node;
OFX::Host::Param::Descriptor& _descriptor;
public:
CustomInstance(std::shared_ptr<PluginNode> 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<QByteArray>()) {
data = variant.toByteArray().toStdString();
return kOfxStatOK;
}
if (variant.canConvert<QString>()) {
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<QByteArray>()) {
data = variant.toByteArray().toStdString();
return kOfxStatOK;
}
if (variant.canConvert<QString>()) {
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);
Core::instance()->undo_stack()->push(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);
Core::instance()->undo_stack()->push(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)
{
}
};
}
}
@@ -196,6 +196,8 @@ NodeParamViewItemBody::NodeParamViewItemBody(
QGridLayout *root_layout = new QGridLayout(this);
int insert_row = 0;
QString current_page;
QString current_group;
QVector<Node *> connected_signals;
@@ -219,6 +221,27 @@ NodeParamViewItemBody::NodeParamViewItemBody(
{ n, input });
if (!(n->GetInputFlags(input) & kInputFlagHidden)) {
QString page_label = n->GetInputProperty(input, QStringLiteral("ui_page")).toString();
QString group_label = n->GetInputProperty(input, QStringLiteral("ui_group")).toString();
if (!page_label.isEmpty() && page_label != current_page) {
QLabel *page_title = new QLabel(page_label, this);
QFont f = page_title->font();
f.setBold(true);
page_title->setFont(f);
root_layout->addWidget(page_title, insert_row, 0, 1, 10);
insert_row++;
current_page = page_label;
current_group.clear();
}
if (!group_label.isEmpty() && group_label != current_group) {
QLabel *group_title = new QLabel(group_label, this);
QFont f = group_title->font();
f.setBold(true);
group_title->setFont(f);
root_layout->addWidget(group_title, insert_row, 0, 1, 10);
insert_row++;
current_group = group_label;
}
CreateWidgets(root_layout, n, input, -1, insert_row);
insert_row++;
@@ -261,9 +261,16 @@ void NodeParamViewWidgetBridge::WidgetCallback()
case NodeValue::kVideoParams:
case NodeValue::kAudioParams:
case NodeValue::kSubtitleParams:
case NodeValue::kBinary:
case NodeValue::kDataTypeCount:
break;
case NodeValue::kBinary: {
NodeParamViewTextEdit *line_edit =
new NodeParamViewTextEdit(parent);
widgets_.append(line_edit);
connect(line_edit, &NodeParamViewTextEdit::textEdited, this,
&NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeValue::kInt: {
// Widget is a IntegerSlider
IntegerSlider *slider = static_cast<IntegerSlider *>(sender());
@@ -342,6 +349,16 @@ void NodeParamViewWidgetBridge::WidgetCallback()
0);
break;
}
case NodeValue::kBinary: {
QString text = static_cast<NodeParamViewTextEdit *>(sender())->text();
QByteArray raw = text.toUtf8();
QByteArray decoded = QByteArray::fromBase64(raw);
if (decoded.isEmpty() && !raw.isEmpty()) {
decoded = raw;
}
SetInputValue(decoded, 0);
break;
}
case NodeValue::kBoolean: {
// Widget is a QCheckBox
SetInputValue(static_cast<QCheckBox *>(sender())->isChecked(), 0);
@@ -440,9 +457,15 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
case NodeValue::kVideoParams:
case NodeValue::kAudioParams:
case NodeValue::kSubtitleParams:
case NodeValue::kBinary:
case NodeValue::kDataTypeCount:
break;
case NodeValue::kBinary: {
NodeParamViewTextEdit *e =
static_cast<NodeParamViewTextEdit *>(widgets_.first());
QByteArray bytes = GetInnerInput().GetValueAtTime(node_time).toByteArray();
e->setTextPreservingCursor(QString::fromUtf8(bytes.toBase64()));
break;
}
case NodeValue::kInt: {
static_cast<IntegerSlider *>(widgets_.first())
->SetValue(GetInnerInput().GetValueAtTime(node_time).toLongLong());