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:
@@ -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 插件会根据项目尺寸、扫描线场信息做渲染决策。
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user