implemented value node
Also implements changes necessary to support an input data type that changes. Much of that foundation was built in `nodearchchanges`, but hadn't been finalized. This commit finalizes and provides a reference implementation/test with the "Value" node. Fixes #1443
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
#include "project/folder/folder.h"
|
||||
#include "project/footage/footage.h"
|
||||
#include "project/sequence/sequence.h"
|
||||
#include "node/input/value/valuenode.h"
|
||||
|
||||
namespace olive {
|
||||
QList<Node*> NodeFactory::library_;
|
||||
@@ -234,6 +235,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
|
||||
return new Folder();
|
||||
case kProjectSequence:
|
||||
return new Sequence();
|
||||
case kValueNode:
|
||||
return new ValueNode();
|
||||
|
||||
case kInternalNodeCount:
|
||||
break;
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
kProjectFootage,
|
||||
kProjectFolder,
|
||||
kProjectSequence,
|
||||
kValueNode,
|
||||
|
||||
// Count value
|
||||
kInternalNodeCount
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(value)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "multicamnode.h"
|
||||
|
||||
MultiCamNode::MultiCamNode()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef MULTICAMNODE_H
|
||||
#define MULTICAMNODE_H
|
||||
|
||||
|
||||
class MultiCamNode
|
||||
{
|
||||
public:
|
||||
MultiCamNode();
|
||||
};
|
||||
|
||||
#endif // MULTICAMNODE_H
|
||||
@@ -0,0 +1,22 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2020 Olive 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
node/input/value/valuenode.h
|
||||
node/input/value/valuenode.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,81 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2020 Olive 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "valuenode.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QString ValueNode::kTypeInput = QStringLiteral("type_in");
|
||||
const QString ValueNode::kValueInput = QStringLiteral("value_in");
|
||||
const QVector<NodeValue::Type> ValueNode::kSupportedTypes = {
|
||||
NodeValue::kFloat,
|
||||
NodeValue::kInt,
|
||||
NodeValue::kRational,
|
||||
NodeValue::kVec2,
|
||||
NodeValue::kVec3,
|
||||
NodeValue::kVec4,
|
||||
NodeValue::kColor,
|
||||
NodeValue::kText,
|
||||
NodeValue::kMatrix,
|
||||
NodeValue::kFont,
|
||||
};
|
||||
|
||||
#define super Node
|
||||
|
||||
ValueNode::ValueNode()
|
||||
{
|
||||
AddInput(kTypeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
AddInput(kValueInput, kSupportedTypes.first(), QVariant(), InputFlags(kInputFlagNotConnectable));
|
||||
}
|
||||
|
||||
void ValueNode::Retranslate()
|
||||
{
|
||||
SetInputName(kTypeInput, QStringLiteral("Type"));
|
||||
SetInputName(kValueInput, QStringLiteral("Value"));
|
||||
|
||||
QStringList type_names;
|
||||
type_names.reserve(kSupportedTypes.size());
|
||||
foreach (NodeValue::Type type, kSupportedTypes) {
|
||||
type_names.append(NodeValue::GetPrettyDataTypeName(type));
|
||||
}
|
||||
SetComboBoxStrings(kTypeInput, type_names);
|
||||
}
|
||||
|
||||
NodeValueTable ValueNode::Value(const QString &output, NodeValueDatabase &value) const
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
// Pop combobox value off table because no other node will need it
|
||||
value[kTypeInput].Take(NodeValue::kCombo);
|
||||
|
||||
return value.Merge();
|
||||
}
|
||||
|
||||
void ValueNode::InputValueChangedEvent(const QString &input, int element)
|
||||
{
|
||||
if (input == kTypeInput) {
|
||||
SetInputDataType(kValueInput, kSupportedTypes.at(GetStandardValue(kTypeInput).toInt()));
|
||||
}
|
||||
|
||||
super::InputValueChangedEvent(input, element);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2020 Olive 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef VALUENODE_H
|
||||
#define VALUENODE_H
|
||||
|
||||
#include "node/node.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ValueNode : public Node
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ValueNode();
|
||||
|
||||
NODE_DEFAULT_DESTRUCTOR(ValueNode)
|
||||
|
||||
virtual Node* copy() const override
|
||||
{
|
||||
return new ValueNode();
|
||||
}
|
||||
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Value");
|
||||
}
|
||||
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.value");
|
||||
}
|
||||
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryInput};
|
||||
}
|
||||
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Create a single value that can be connected to various other inputs.");
|
||||
}
|
||||
|
||||
static const QString kTypeInput;
|
||||
static const QString kValueInput;
|
||||
|
||||
virtual void Retranslate() override;
|
||||
|
||||
virtual NodeValueTable Value(const QString &output, NodeValueDatabase &value) const override;
|
||||
|
||||
protected:
|
||||
virtual void InputValueChangedEvent(const QString &input, int element) override;
|
||||
|
||||
private:
|
||||
static const QVector<NodeValue::Type> kSupportedTypes;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // VALUENODE_H
|
||||
@@ -27,14 +27,10 @@
|
||||
namespace olive {
|
||||
|
||||
NodeInputImmediate::NodeInputImmediate(NodeValue::Type type, const SplitValue &default_val) :
|
||||
default_value_(default_val),
|
||||
keyframing_(false)
|
||||
{
|
||||
int track_size = NodeValue::get_number_of_keyframe_tracks(type);
|
||||
|
||||
keyframe_tracks_.resize(track_size);
|
||||
standard_value_.resize(track_size);
|
||||
|
||||
set_split_standard_value(default_val);
|
||||
set_data_type(type);
|
||||
}
|
||||
|
||||
void NodeInputImmediate::set_standard_value_on_track(const QVariant &value, int track)
|
||||
@@ -179,6 +175,16 @@ bool NodeInputImmediate::has_keyframe_at_time(const rational &time) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void NodeInputImmediate::set_data_type(NodeValue::Type type)
|
||||
{
|
||||
int track_size = NodeValue::get_number_of_keyframe_tracks(type);
|
||||
|
||||
keyframe_tracks_.resize(track_size);
|
||||
standard_value_.resize(track_size);
|
||||
|
||||
set_split_standard_value(default_value_);
|
||||
}
|
||||
|
||||
NodeKeyframe *NodeInputImmediate::get_earliest_keyframe() const
|
||||
{
|
||||
NodeKeyframe* earliest = nullptr;
|
||||
|
||||
@@ -151,12 +151,19 @@ public:
|
||||
return (!is_keyframing() || keyframe_tracks_.at(track).isEmpty());
|
||||
}
|
||||
|
||||
void set_data_type(NodeValue::Type type);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Non-keyframed value
|
||||
*/
|
||||
SplitValue standard_value_;
|
||||
|
||||
/**
|
||||
* @brief Default value
|
||||
*/
|
||||
SplitValue default_value_;
|
||||
|
||||
/**
|
||||
* @brief Internal keyframe array
|
||||
*
|
||||
|
||||
+14
-4
@@ -505,10 +505,15 @@ NodeValue::Type Node::GetInputDataType(const QString &id) const
|
||||
|
||||
void Node::SetInputDataType(const QString &id, const NodeValue::Type &type)
|
||||
{
|
||||
Input* i = GetInternalInputData(id);
|
||||
Input* input_meta = GetInternalInputData(id);
|
||||
|
||||
if (i) {
|
||||
i->type = type;
|
||||
if (input_meta) {
|
||||
input_meta->type = type;
|
||||
|
||||
int array_sz = InputArraySize(id);
|
||||
for (int i=-1; i<array_sz; i++) {
|
||||
GetImmediate(id, i)->set_data_type(type);
|
||||
}
|
||||
|
||||
emit InputDataTypeChanged(id, type);
|
||||
} else {
|
||||
@@ -693,7 +698,12 @@ SplitValue Node::GetSplitDefaultValue(const QString &input) const
|
||||
|
||||
QVariant Node::GetSplitDefaultValueOnTrack(const QString &input, int track) const
|
||||
{
|
||||
return GetSplitDefaultValue(input).at(track);
|
||||
SplitValue val = GetSplitDefaultValue(input);
|
||||
if (track < val.size()) {
|
||||
return val.at(track);
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<NodeKeyframeTrack> &Node::GetKeyframeTracks(const QString &input, int element) const
|
||||
|
||||
@@ -36,6 +36,9 @@ const int NodeParamViewItemBody::kKeyControlColumn = 10;
|
||||
const int NodeParamViewItemBody::kArrayInsertColumn = kKeyControlColumn-1;
|
||||
const int NodeParamViewItemBody::kArrayRemoveColumn = kArrayInsertColumn-1;
|
||||
|
||||
// 0 is for the array collapse button, 1 is for the main label, widgets start at 2
|
||||
const int NodeParamViewItemBody::kWidgetStartColumn = 2;
|
||||
|
||||
#define super QDockWidget
|
||||
|
||||
NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
@@ -261,6 +264,10 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, Node *node, const
|
||||
|
||||
InputUI ui_objects;
|
||||
|
||||
// Store layout and row
|
||||
ui_objects.layout = layout;
|
||||
ui_objects.row = row;
|
||||
|
||||
// Add descriptor label
|
||||
ui_objects.main_label = new QLabel();
|
||||
|
||||
@@ -303,23 +310,24 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, Node *node, const
|
||||
|
||||
// Create a widget/input bridge for this input
|
||||
ui_objects.widget_bridge = new NodeParamViewWidgetBridge(NodeInput(node, input, element), this);
|
||||
connect(ui_objects.widget_bridge, &NodeParamViewWidgetBridge::WidgetsRecreated, this, &NodeParamViewItemBody::ReplaceWidgets);
|
||||
connect(ui_objects.widget_bridge, &NodeParamViewWidgetBridge::ArrayWidgetDoubleClicked, this, &NodeParamViewItemBody::ToggleArrayExpanded);
|
||||
|
||||
// 0 is for the array collapse button, 1 is for the main label, widgets start at 2
|
||||
const int widget_start = 2;
|
||||
// Place widgets into layout
|
||||
PlaceWidgetsFromBridge(layout, ui_objects.widget_bridge, row);
|
||||
|
||||
// Add widgets for this parameter to the layout
|
||||
for (int i=0; i<ui_objects.widget_bridge->widgets().size(); i++) {
|
||||
QWidget* w = ui_objects.widget_bridge->widgets().at(i);
|
||||
|
||||
layout->addWidget(w, row, i+widget_start);
|
||||
layout->addWidget(w, row, i+kWidgetStartColumn);
|
||||
}
|
||||
|
||||
if (node->IsInputConnectable(input)) {
|
||||
// Create clickable label used when an input is connected
|
||||
ui_objects.connected_label = new NodeParamViewConnectedLabel(input_ref);
|
||||
connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);
|
||||
layout->addWidget(ui_objects.connected_label, row, widget_start);
|
||||
layout->addWidget(ui_objects.connected_label, row, kWidgetStartColumn);
|
||||
}
|
||||
|
||||
// Add keyframe control to this layout if parameter is keyframable
|
||||
@@ -418,6 +426,16 @@ void NodeParamViewItemBody::UpdateUIForEdgeConnection(const NodeInput& input)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::PlaceWidgetsFromBridge(QGridLayout* layout, NodeParamViewWidgetBridge *bridge, int row)
|
||||
{
|
||||
// Add widgets for this parameter to the layout
|
||||
for (int i=0; i<bridge->widgets().size(); i++) {
|
||||
QWidget* w = bridge->widgets().at(i);
|
||||
|
||||
layout->addWidget(w, row, i+kWidgetStartColumn);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::ArrayCollapseBtnPressed(bool checked)
|
||||
{
|
||||
const NodeInputPair& input = array_collapse_buttons_.key(static_cast<CollapseButton*>(sender()));
|
||||
@@ -514,6 +532,12 @@ void NodeParamViewItemBody::ToggleArrayExpanded()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::ReplaceWidgets(const NodeInput &input)
|
||||
{
|
||||
InputUI ui = input_ui_map_.value(input);
|
||||
PlaceWidgetsFromBridge(ui.layout, ui.widget_bridge, ui.row);
|
||||
}
|
||||
|
||||
NodeParamViewItemBody::InputUI::InputUI() :
|
||||
main_label(nullptr),
|
||||
widget_bridge(nullptr),
|
||||
|
||||
@@ -97,6 +97,8 @@ private:
|
||||
|
||||
void UpdateUIForEdgeConnection(const NodeInput &input);
|
||||
|
||||
void PlaceWidgetsFromBridge(QGridLayout *layout, NodeParamViewWidgetBridge* bridge, int row);
|
||||
|
||||
struct InputUI {
|
||||
InputUI();
|
||||
|
||||
@@ -104,6 +106,8 @@ private:
|
||||
NodeParamViewWidgetBridge* widget_bridge;
|
||||
NodeParamViewConnectedLabel* connected_label;
|
||||
NodeParamViewKeyframeControl* key_control;
|
||||
QGridLayout* layout;
|
||||
int row;
|
||||
|
||||
NodeParamViewArrayButton* array_insert_btn;
|
||||
NodeParamViewArrayButton* array_remove_btn;
|
||||
@@ -132,6 +136,8 @@ private:
|
||||
static const int kArrayInsertColumn;
|
||||
static const int kArrayRemoveColumn;
|
||||
|
||||
static const int kWidgetStartColumn;
|
||||
|
||||
private slots:
|
||||
void EdgeChanged(const NodeOutput &output, const NodeInput &input);
|
||||
|
||||
@@ -147,6 +153,8 @@ private slots:
|
||||
|
||||
void ToggleArrayExpanded();
|
||||
|
||||
void ReplaceWidgets(const NodeInput& input);
|
||||
|
||||
};
|
||||
|
||||
class NodeParamViewItem : public QDockWidget
|
||||
|
||||
@@ -49,6 +49,7 @@ NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(const NodeInput &input, QOb
|
||||
|
||||
connect(input_.node(), &Node::ValueChanged, this, &NodeParamViewWidgetBridge::InputValueChanged);
|
||||
connect(input_.node(), &Node::InputPropertyChanged, this, &NodeParamViewWidgetBridge::PropertyChanged);
|
||||
connect(input_.node(), &Node::InputDataTypeChanged, this, &NodeParamViewWidgetBridge::InputDataTypeChanged);
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::SetTime(const rational &time)
|
||||
@@ -756,6 +757,22 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString& input, const QStr
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::InputDataTypeChanged(const QString &input, NodeValue::Type type)
|
||||
{
|
||||
Q_UNUSED(type)
|
||||
if (input == this->input_.input()) {
|
||||
// Delete all widgets
|
||||
qDeleteAll(widgets_);
|
||||
widgets_.clear();
|
||||
|
||||
// Create new widgets
|
||||
CreateWidgets();
|
||||
|
||||
// Signal that widgets are new
|
||||
emit WidgetsRecreated(input_);
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeParamViewScrollBlocker::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(watched)
|
||||
|
||||
@@ -52,6 +52,8 @@ public:
|
||||
signals:
|
||||
void ArrayWidgetDoubleClicked();
|
||||
|
||||
void WidgetsRecreated(const NodeInput& input);
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
|
||||
@@ -85,6 +87,8 @@ private slots:
|
||||
|
||||
void PropertyChanged(const QString &input, const QString& key, const QVariant& value);
|
||||
|
||||
void InputDataTypeChanged(const QString& input, NodeValue::Type type);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user