engine: node parameter panel migrates to the facade
- new facade API: set_input_at_time (element addressing, track=-1 for all components at once), set_input_string_at_time, frame_time_base, array_insert_at/remove_at, disconnect_ex (element-aware), and keyframes_set_type_many (first cross-track keyframe op, addressed by (time,track) pairs) - the widget bridge's commit funnel, color path, array ops, label disconnect, and keyframe set-type actions in keyframeview/curvewidget now go through the facade; keyframeviewundo.h loses two consumers - deliberate leftovers with rationale: keyframecontrol's multi-track composite ops (documented track-0-only limitation of the keyframe family), keyframeproperties dialog (needs a set_time primitive), curveview's drag UX, and NodeInputDragger (already engine-side)
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
#include "common/qtutils.h"
|
||||
#include "core.h"
|
||||
#include "node/node.h"
|
||||
#include "node/nodeundo.h"
|
||||
#include "oakengine/node.h"
|
||||
#include "widget/collapsebutton/collapsebutton.h"
|
||||
#include "widget/menu/menu.h"
|
||||
|
||||
@@ -150,9 +150,11 @@ void NodeParamViewConnectedLabel::show_label_context_menu()
|
||||
|
||||
QAction *disconnect_action = m.addAction(tr("Disconnect"));
|
||||
connect(disconnect_action, &QAction::triggered, this, [this]() {
|
||||
Core::instance()->undo_stack()->push(
|
||||
new NodeEdgeRemoveCommand(connected_node_, input_),
|
||||
Node::get_disconnect_command_string(connected_node_, input_));
|
||||
// Through the liboakengine C ABI facade (one undoable command,
|
||||
// array element included, same as the old NodeEdgeRemoveCommand).
|
||||
oakengine_node_disconnect_ex(
|
||||
reinterpret_cast<OakEngineNode *>(input_.node()),
|
||||
input_.input().toUtf8().constData(), input_.element());
|
||||
});
|
||||
|
||||
m.exec(QCursor::pos());
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "core.h"
|
||||
#include "dialog/speedduration/speeddurationdialog.h"
|
||||
#include "node/group/group.h"
|
||||
#include "node/nodeundo.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "oakengine/node.h"
|
||||
#include "pluginSupport/oliveplugininstance.h"
|
||||
|
||||
namespace olive
|
||||
@@ -630,13 +629,12 @@ void NodeParamViewItemBody::array_append_clicked()
|
||||
if (it.value().append_btn == sender()) {
|
||||
NodeInput real_input = NodeGroup::resolve_input(
|
||||
NodeInput(it.key().node, it.key().input));
|
||||
Core::instance()->undo_stack()->push(
|
||||
new NodeArrayInsertCommand(real_input.node(),
|
||||
real_input.input(),
|
||||
real_input.get_array_size()),
|
||||
tr("Appended Array Element In %1 - %2")
|
||||
.arg(real_input.node()->get_label_and_name(),
|
||||
real_input.get_input_name()));
|
||||
// Through the liboakengine C ABI facade (one undoable command,
|
||||
// same as the old NodeArrayInsertCommand push).
|
||||
oakengine_node_array_insert_at(
|
||||
reinterpret_cast<OakEngineNode *>(real_input.node()),
|
||||
real_input.input().toUtf8().constData(),
|
||||
real_input.get_array_size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -648,10 +646,10 @@ void NodeParamViewItemBody::array_insert_clicked()
|
||||
if (it.value().array_insert_btn == sender()) {
|
||||
// Found our input and element
|
||||
NodeInput ic = NodeGroup::resolve_input(it.key());
|
||||
Core::instance()->undo_stack()->push(
|
||||
new NodeArrayInsertCommand(ic.node(), ic.input(), ic.element()),
|
||||
tr("Inserted Array Element In %1 - %2")
|
||||
.arg(ic.node()->get_label_and_name(), ic.get_input_name()));
|
||||
// Through the liboakengine C ABI facade (one undoable command).
|
||||
oakengine_node_array_insert_at(
|
||||
reinterpret_cast<OakEngineNode *>(ic.node()),
|
||||
ic.input().toUtf8().constData(), ic.element());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -663,10 +661,10 @@ void NodeParamViewItemBody::array_remove_clicked()
|
||||
if (it.value().array_remove_btn == sender()) {
|
||||
// Found our input and element
|
||||
NodeInput ic = NodeGroup::resolve_input(it.key());
|
||||
Core::instance()->undo_stack()->push(
|
||||
new NodeArrayRemoveCommand(ic.node(), ic.input(), ic.element()),
|
||||
tr("Removed Array Element In %1 - %2")
|
||||
.arg(ic.node()->get_label_and_name(), ic.get_input_name()));
|
||||
// Through the liboakengine C ABI facade (one undoable command).
|
||||
oakengine_node_array_remove_at(
|
||||
reinterpret_cast<OakEngineNode *>(ic.node()),
|
||||
ic.input().toUtf8().constData(), ic.element());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "nodeparamviewarraywidget.h"
|
||||
#include "nodeparamviewtextedit.h"
|
||||
#include "oakengine/node.h"
|
||||
#include "render/lutlibrary.h"
|
||||
#include "undo/undostack.h"
|
||||
#include "widget/bezier/bezierwidget.h"
|
||||
@@ -75,6 +76,74 @@ int get_slider_count(NodeValue::Type type)
|
||||
return NodeValue::get_number_of_keyframe_tracks(type);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Map a panel widget's per-track scalar QVariant into the facade POD.
|
||||
// Returns false for types that have no facade mapping (the caller keeps
|
||||
// the legacy path for those).
|
||||
bool variant_to_c_value(NodeValue::Type type, const QVariant &value,
|
||||
oak_node_value *out)
|
||||
{
|
||||
memset(out, 0, sizeof(*out));
|
||||
switch (type) {
|
||||
case NodeValue::k_int:
|
||||
out->type = OAK_NODE_VALUE_INT;
|
||||
out->num = value.toLongLong();
|
||||
return true;
|
||||
case NodeValue::k_combo:
|
||||
out->type = OAK_NODE_VALUE_COMBO;
|
||||
out->num = value.toLongLong();
|
||||
return true;
|
||||
case NodeValue::k_float:
|
||||
case NodeValue::k_bezier:
|
||||
out->type = OAK_NODE_VALUE_FLOAT;
|
||||
out->f[0] = value.toDouble();
|
||||
return true;
|
||||
case NodeValue::k_boolean:
|
||||
out->type = OAK_NODE_VALUE_BOOL;
|
||||
out->num = value.toBool() ? 1 : 0;
|
||||
return true;
|
||||
case NodeValue::k_rational: {
|
||||
const Rational r = value.value<Rational>();
|
||||
out->type = OAK_NODE_VALUE_RATIONAL;
|
||||
out->num = r.numerator();
|
||||
out->den = r.denominator();
|
||||
return true;
|
||||
}
|
||||
case NodeValue::k_color:
|
||||
out->type = OAK_NODE_VALUE_COLOR;
|
||||
out->f[0] = value.toDouble();
|
||||
return true;
|
||||
case NodeValue::k_vec2:
|
||||
out->type = OAK_NODE_VALUE_VEC2;
|
||||
out->f[0] = value.toDouble();
|
||||
return true;
|
||||
case NodeValue::k_vec3:
|
||||
out->type = OAK_NODE_VALUE_VEC3;
|
||||
out->f[0] = value.toDouble();
|
||||
return true;
|
||||
case NodeValue::k_vec4:
|
||||
out->type = OAK_NODE_VALUE_VEC4;
|
||||
out->f[0] = value.toDouble();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert rational node time to the facade's frame timestamps using the
|
||||
// facade's own timebase (so the round trip is exact).
|
||||
int64_t node_time_to_ts(OakEngineNode *node, const Rational &time)
|
||||
{
|
||||
int tbn = 0, tbd = 0;
|
||||
oakengine_node_frame_time_base(node, &tbn, &tbd);
|
||||
return Timecode::time_to_timestamp(time, Rational(tbn, tbd),
|
||||
Timecode::k_round);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void NodeParamViewWidgetBridge::create_widgets()
|
||||
{
|
||||
QWidget *parent = dynamic_cast<QWidget *>(this->parent());
|
||||
@@ -236,11 +305,37 @@ void NodeParamViewWidgetBridge::create_widgets()
|
||||
|
||||
void NodeParamViewWidgetBridge::set_input_value(const QVariant &value, int track)
|
||||
{
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
// POD values go through the liboakengine C ABI facade (one undoable
|
||||
// command with the same set-value-at-time semantics as the old
|
||||
// app-side assembly); types without a facade mapping keep the legacy
|
||||
// undo assembly below.
|
||||
const NodeInput &input = get_inner_input();
|
||||
oak_node_value c_value;
|
||||
if (!variant_to_c_value(get_data_type(), value, &c_value)) {
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
set_input_value_internal(value, track, command, true);
|
||||
Core::instance()->undo_stack()->push(command, get_command_name());
|
||||
return;
|
||||
}
|
||||
|
||||
set_input_value_internal(value, track, command, true);
|
||||
oakengine_node_set_input_at_time(
|
||||
reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
input.input().toUtf8().constData(), input.element(),
|
||||
node_time_to_ts(reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
get_current_time_as_node_time()),
|
||||
track, &c_value, 1);
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(command, get_command_name());
|
||||
void NodeParamViewWidgetBridge::set_string_value(const QString &value)
|
||||
{
|
||||
// String-family inputs (file/text/font/str_combo) through the facade.
|
||||
const NodeInput &input = get_inner_input();
|
||||
oakengine_node_set_input_string_at_time(
|
||||
reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
input.input().toUtf8().constData(), input.element(),
|
||||
node_time_to_ts(reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
get_current_time_as_node_time()),
|
||||
value.toUtf8().constData());
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::set_input_value_internal(
|
||||
@@ -336,7 +431,7 @@ void NodeParamViewWidgetBridge::widget_callback()
|
||||
break;
|
||||
}
|
||||
case NodeValue::k_file: {
|
||||
set_input_value(static_cast<FileField *>(sender())->get_filename(), 0);
|
||||
set_string_value(static_cast<FileField *>(sender())->get_filename());
|
||||
break;
|
||||
}
|
||||
case NodeValue::k_color: {
|
||||
@@ -345,15 +440,27 @@ void NodeParamViewWidgetBridge::widget_callback()
|
||||
FloatSlider *slider = static_cast<FloatSlider *>(sender());
|
||||
process_slider(slider, slider->get_value());
|
||||
} else {
|
||||
// Sender is a ColorButton
|
||||
// Sender is a ColorButton: all four components go through the
|
||||
// facade in one undoable command (track -1). The
|
||||
// color-management input properties are not undoable in the
|
||||
// engine and stay direct (same as the old code).
|
||||
ManagedColor c = static_cast<ColorButton *>(sender())->get_color();
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
set_input_value_internal(c.red(), 0, command, false);
|
||||
set_input_value_internal(c.green(), 1, command, false);
|
||||
set_input_value_internal(c.blue(), 2, command, false);
|
||||
set_input_value_internal(c.alpha(), 3, command, false);
|
||||
const NodeInput &input = get_inner_input();
|
||||
oak_node_value c_value;
|
||||
memset(&c_value, 0, sizeof(c_value));
|
||||
c_value.type = OAK_NODE_VALUE_COLOR;
|
||||
c_value.f[0] = c.red();
|
||||
c_value.f[1] = c.green();
|
||||
c_value.f[2] = c.blue();
|
||||
c_value.f[3] = c.alpha();
|
||||
oakengine_node_set_input_at_time(
|
||||
reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
input.input().toUtf8().constData(), input.element(),
|
||||
node_time_to_ts(
|
||||
reinterpret_cast<OakEngineNode *>(input.node()),
|
||||
get_current_time_as_node_time()),
|
||||
-1, &c_value, 0);
|
||||
|
||||
Node *n = get_inner_input().node();
|
||||
n->blockSignals(true);
|
||||
@@ -369,15 +476,12 @@ void NodeParamViewWidgetBridge::widget_callback()
|
||||
QStringLiteral("col_look"),
|
||||
c.color_output().look());
|
||||
n->blockSignals(false);
|
||||
|
||||
Core::instance()->undo_stack()->push(command, get_command_name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeValue::k_text: {
|
||||
// Sender is a NodeParamViewRichText
|
||||
set_input_value(static_cast<NodeParamViewTextEdit *>(sender())->text(),
|
||||
0);
|
||||
set_string_value(static_cast<NodeParamViewTextEdit *>(sender())->text());
|
||||
break;
|
||||
}
|
||||
case NodeValue::k_binary: {
|
||||
@@ -397,8 +501,8 @@ void NodeParamViewWidgetBridge::widget_callback()
|
||||
}
|
||||
case NodeValue::k_font: {
|
||||
// Widget is a QFontComboBox
|
||||
set_input_value(
|
||||
static_cast<QFontComboBox *>(sender())->currentFont().family(), 0);
|
||||
set_string_value(
|
||||
static_cast<QFontComboBox *>(sender())->currentFont().family());
|
||||
break;
|
||||
}
|
||||
case NodeValue::k_combo: {
|
||||
@@ -421,9 +525,9 @@ void NodeParamViewWidgetBridge::widget_callback()
|
||||
QComboBox *cb = static_cast<QComboBox *>(widgets_.first());
|
||||
const QVariant data = cb->currentData();
|
||||
if (data.isValid()) {
|
||||
set_input_value(data.toString(), 0);
|
||||
set_string_value(data.toString());
|
||||
} else {
|
||||
set_input_value(cb->currentText(), 0);
|
||||
set_string_value(cb->currentText());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ private:
|
||||
|
||||
void set_input_value(const QVariant &value, int track);
|
||||
|
||||
void set_string_value(const QString &value);
|
||||
|
||||
void set_input_value_internal(const QVariant &value, int track,
|
||||
MultiUndoCommand *command,
|
||||
bool insert_on_all_tracks_if_no_key);
|
||||
|
||||
Reference in New Issue
Block a user