new undo system

Also enables undoing when working with node input arrays
This commit is contained in:
itsmattkc
2021-01-29 16:10:34 +11:00
parent 4e5db91c17
commit ad4b83a098
69 changed files with 1218 additions and 837 deletions
+1
View File
@@ -43,6 +43,7 @@ set(OLIVE_SOURCES
node/node.cpp
node/nodecopypaste.h
node/nodecopypaste.cpp
node/splitvalue.h
node/traverser.h
node/traverser.cpp
node/value.h
+1 -1
View File
@@ -27,7 +27,7 @@ namespace olive {
PolygonGenerator::PolygonGenerator()
{
points_input_ = new NodeInput(this, QStringLiteral("points_in"), NodeValue::kVec2);
points_input_ = new NodeInput(this, QStringLiteral("points_in"), NodeValue::kVec2, QVector2D(0, 0));
points_input_->SetIsArray(true);
color_input_ = new NodeInput(this, QStringLiteral("color_in"), NodeValue::kColor, QVariant::fromValue(Color(1.0, 1.0, 1.0)));
+137 -76
View File
@@ -23,14 +23,16 @@
#include "common/bezier.h"
#include "common/lerp.h"
#include "common/xmlutils.h"
#include "core.h"
#include "node.h"
#include "project/item/footage/stream.h"
#include "widget/nodeview/nodeviewundo.h"
#define super NodeConnectable
namespace olive {
NodeInput::NodeInput(Node* parent, const QString& id, NodeValue::Type type, const QVector<QVariant> &default_value)
NodeInput::NodeInput(Node* parent, const QString& id, NodeValue::Type type, const SplitValue &default_value)
{
Init(parent, id, type, default_value);
}
@@ -42,7 +44,7 @@ NodeInput::NodeInput(Node *parent, const QString &id, NodeValue::Type type, cons
NodeInput::NodeInput(Node* parent, const QString &id, NodeValue::Type type)
{
Init(parent, id, type, QVector<QVariant>());
Init(parent, id, type, SplitValue());
}
NodeInput::~NodeInput()
@@ -217,7 +219,16 @@ void NodeInput::childEvent(QChildEvent *event)
}
}
void NodeInput::Init(Node* parent, const QString &id, NodeValue::Type type, const QVector<QVariant>& default_val)
void NodeInput::ClearElement(int index)
{
GetImmediate(index)->delete_all_keyframes();
SetIsKeyframing(false, index);
SetSplitStandardValue(default_value_, index);
}
void NodeInput::Init(Node* parent, const QString &id, NodeValue::Type type, const SplitValue& default_val)
{
setParent(parent);
@@ -381,11 +392,25 @@ void NodeInput::SaveImmediate(QXmlStreamWriter* writer, int element) const
}
}
void NodeInput::ChangeArraySizeInternal(int size)
void NodeInput::ArrayResizeInternal(int size)
{
array_size_ = size;
emit ArraySizeChanged(array_size_);
emit ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX), -1);
if (array_size_ != size) {
// Update array size
if (array_size_ < size) {
// Size is larger, create any immediates that don't exist
for (int i=subinputs_.size(); i<size; i++) {
subinputs_.append(CreateImmediate());
}
// Note that we do not delete any immediates when decreasing size since the user might still
// want that data. Therefore it's important to note that array_size_ does NOT necessarily
// equal subinputs_.size()
}
array_size_ = size;
emit ArraySizeChanged(array_size_);
emit ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX), -1);
}
}
NodeInputImmediate *NodeInput::CreateImmediate()
@@ -440,79 +465,95 @@ QVector<Node *> NodeInput::GetImmediateDependencies() const
return GetDependencies(false, false);
}
void NodeInput::ArrayInsert(int index)
void NodeInput::ArrayAppend(bool undoable)
{
// Add new input
subinputs_.insert(index, CreateImmediate());
ChangeArraySizeInternal(array_size_ + 1);
// Move connections down
std::map<int, Node*> copied_edges = edges();
for (auto it=copied_edges.crbegin(); it!=copied_edges.crend(); it++) {
if (it->first >= index) {
// Disconnect this and reconnect it one element down
DisconnectEdge(it->second, this, it->first);
ConnectEdge(it->second, this, it->first + 1);
}
}
ArrayResize(ArraySize() + 1, undoable);
}
void NodeInput::ArrayRemove(int index)
void NodeInput::ArrayInsert(int index, bool undoable)
{
// Remove input
delete subinputs_.takeAt(index);
ChangeArraySizeInternal(array_size_ - 1);
if (undoable) {
Core::instance()->undo_stack()->push(new ArrayInsertCommand(this, index));
} else {
// Add new input
ArrayResizeInternal(ArraySize() + 1);
// Move connections up
std::map<int, Node*> copied_edges = edges();
for (auto it=copied_edges.cbegin(); it!=copied_edges.cend(); it++) {
if (it->first >= index) {
// Disconnect this and reconnect it one element up if it's not the element being removed
DisconnectEdge(it->second, this, it->first);
if (it->first > index) {
ConnectEdge(it->second, this, it->first - 1);
}
}
}
}
void NodeInput::ArrayPrepend()
{
ArrayInsert(0);
}
void NodeInput::ArrayResize(int size)
{
if (array_size_ != size) {
// Update array size
if (array_size_ < size) {
// Size is larger, create any immediates that don't exist
for (int i=subinputs_.size(); i<size; i++) {
subinputs_.append(CreateImmediate());
// Move connections down
std::map<int, Node*> copied_edges = edges();
for (auto it=copied_edges.crbegin(); it!=copied_edges.crend(); it++) {
if (it->first >= index) {
// Disconnect this and reconnect it one element down
DisconnectEdge(it->second, this, it->first);
ConnectEdge(it->second, this, it->first + 1);
}
}
ChangeArraySizeInternal(size);
if (array_size_ > size) {
// Decreasing in size, disconnect any extraneous edges
for (int i=size; i<array_size_; i++) {
try {
DisconnectEdge(edges().at(i), this, i);
} catch (std::out_of_range&) {}
}
// Note that we do not delete any immediates since the user might still want that data.
// Therefore it's important to note that array_size_ does NOT necessarily equal subinputs_.size()
// Shift values and keyframes up one element
for (int i=ArraySize()-1; i>index; i--) {
CopyValuesOfElement(this, this, i-1, i);
}
// Reset value of element we just "inserted"
ClearElement(index);
}
}
void NodeInput::ArrayRemoveLast()
void NodeInput::ArrayRemove(int index, bool undoable)
{
ArrayResize(ArraySize() - 1);
if (undoable) {
Core::instance()->undo_stack()->push(new ArrayRemoveCommand(this, index));
} else {
// Remove input
ArrayResizeInternal(ArraySize() - 1);
// Move connections up
std::map<int, Node*> copied_edges = edges();
for (auto it=copied_edges.cbegin(); it!=copied_edges.cend(); it++) {
if (it->first >= index) {
// Disconnect this and reconnect it one element up if it's not the element being removed
DisconnectEdge(it->second, this, it->first);
if (it->first > index) {
ConnectEdge(it->second, this, it->first - 1);
}
}
}
// Shift values and keyframes down one element
for (int i=index; i<ArraySize(); i++) {
// Copying ArraySize()+1 is actually legal because immediates are never deleted
CopyValuesOfElement(this, this, i+1, i);
}
// Reset value of last element
ClearElement(ArraySize());
}
}
void NodeInput::ArrayPrepend(bool undoable)
{
ArrayInsert(0, undoable);
}
void NodeInput::ArrayResize(int size, bool undoable)
{
if (array_size_ == size) {
return;
}
ArrayResizeCommand* c = new ArrayResizeCommand(this, size);
if (undoable) {
Core::instance()->undo_stack()->push(c);
} else {
c->redo();
delete c;
}
}
void NodeInput::ArrayRemoveLast(bool undoable)
{
ArrayResize(ArraySize() - 1, undoable);
}
QVariant NodeInput::GetValueAtTime(const rational &time, int element) const
@@ -520,9 +561,9 @@ QVariant NodeInput::GetValueAtTime(const rational &time, int element) const
return NodeValue::combine_track_values_into_normal_value(data_type_, GetSplitValuesAtTime(time, element));
}
QVector<QVariant> NodeInput::GetSplitValuesAtTime(const rational &time, int element) const
SplitValue NodeInput::GetSplitValuesAtTime(const rational &time, int element) const
{
QVector<QVariant> vals;
SplitValue vals;
int nb_tracks = GetNumberOfKeyframeTracks();
@@ -669,26 +710,31 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
}
}
void NodeInput::CopyValuesOfElement(NodeInput *src, NodeInput *dst, int element)
void NodeInput::CopyValuesOfElement(NodeInput *src, NodeInput *dst, int src_element, int dst_element)
{
if (dst_element >= dst->subinputs_.size()) {
qDebug() << "Ignored destination element that was out of array bounds";
return;
}
// Copy standard value
dst->SetSplitStandardValue(src->GetSplitStandardValue(element), element);
dst->SetSplitStandardValue(src->GetSplitStandardValue(src_element), dst_element);
// Copy keyframes
dst->GetImmediate(element)->delete_all_keyframes();
foreach (const NodeKeyframeTrack& track, src->GetImmediate(element)->keyframe_tracks()) {
dst->GetImmediate(dst_element)->delete_all_keyframes();
foreach (const NodeKeyframeTrack& track, src->GetImmediate(src_element)->keyframe_tracks()) {
foreach (NodeKeyframe* key, track) {
key->copy(dst);
key->copy(dst_element, dst);
}
}
// Copy keyframing state
if (src->IsKeyframable()) {
dst->SetIsKeyframing(src->IsKeyframing(element), element);
dst->SetIsKeyframing(src->IsKeyframing(src_element), dst_element);
}
// If this is the root of an array, copy the array size
if (element == -1) {
if (src_element == -1 && dst_element == -1) {
dst->ArrayResize(src->ArraySize());
}
}
@@ -839,4 +885,19 @@ uint qHash(const NodeInput::KeyframeTrackReference &ref, uint seed)
return qHash(ref.input, seed) ^ qHash(ref.element, seed) ^ qHash(ref.track, seed);
}
Project *NodeInput::ArrayRemoveCommand::GetRelevantProject() const
{
return input_->parent()->parent()->project();
}
Project *NodeInput::ArrayResizeCommand::GetRelevantProject() const
{
return input_->parent()->parent()->project();
}
Project *NodeInput::ArrayInsertCommand::GetRelevantProject() const
{
return input_->parent()->parent()->project();
}
}
+155 -20
View File
@@ -26,6 +26,8 @@
#include "node/connectable.h"
#include "node/inputimmediate.h"
#include "node/value.h"
#include "splitvalue.h"
#include "undo/undocommand.h"
namespace olive {
@@ -47,7 +49,7 @@ public:
* saving/loading data from this Node so that parameter order can be changed without issues loading data saved by an
* older version. This of course assumes that parameters don't change their ID.
*/
NodeInput(Node* parent, const QString &id, NodeValue::Type type, const QVector<QVariant>& default_value);
NodeInput(Node* parent, const QString &id, NodeValue::Type type, const SplitValue& default_value);
NodeInput(Node* parent, const QString &id, NodeValue::Type type, const QVariant& default_value);
NodeInput(Node* parent, const QString &id, NodeValue::Type type);
@@ -176,7 +178,7 @@ public:
/**
* @brief Get non-keyframed value split into components (the way it's stored)
*/
const QVector<QVariant>& GetSplitStandardValue(int element = -1) const
const SplitValue& GetSplitStandardValue(int element = -1) const
{
return GetImmediate(element)->get_split_standard_value();
}
@@ -197,7 +199,7 @@ public:
SetSplitStandardValue(NodeValue::split_normal_value_into_track_values(data_type_, value), element);
}
void SetSplitStandardValue(const QVector<QVariant>& value, int element = -1)
void SetSplitStandardValue(const SplitValue& value, int element = -1)
{
GetImmediate(element)->set_split_standard_value(value);
@@ -231,7 +233,11 @@ public:
*/
static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true, bool traverse_arrays = true);
static void CopyValuesOfElement(NodeInput* source, NodeInput* dst, int element);
static void CopyValuesOfElement(NodeInput* source, NodeInput* dst, int src_element, int dst_element);
static void CopyValuesOfElement(NodeInput* source, NodeInput* dst, int element)
{
CopyValuesOfElement(source, dst, element, element);
}
QStringList get_combobox_strings() const;
@@ -244,7 +250,7 @@ public:
return NodeValue::combine_track_values_into_normal_value(data_type_, default_value_);
}
const QVector<QVariant>& GetSplitDefaultValue() const
const SplitValue& GetSplitDefaultValue() const
{
return default_value_;
}
@@ -279,33 +285,36 @@ public:
void SetIsKeyframing(bool keyframing, int element)
{
Q_ASSERT(IsKeyframable());
if (IsKeyframable()) {
qDebug() << "Ignored set keyframing because this input is not keyframable";
return;
}
GetImmediate(element)->set_is_keyframing(keyframing);
emit KeyframeEnableChanged(keyframing, element);
}
void ArrayAppend()
{
ArrayResize(ArraySize() + 1);
}
/// Alias for ArrayResize(ArraySize() + 1)
void ArrayAppend(bool undoable = false);
void ArrayInsert(int index);
void ArrayInsert(int index, bool undoable = false);
void ArrayRemove(int index);
void ArrayRemove(int index, bool undoable = false);
void ArrayPrepend();
/// Alias for ArrayInsert(0)
void ArrayPrepend(bool undoable = false);
void ArrayResize(int size);
void ArrayResize(int size, bool undoable = false);
/// Alias for ArrayResize(ArraySize() - 1)
void ArrayRemoveLast(bool undoable = false);
int ArraySize() const
{
return array_size_;
}
void ArrayRemoveLast();
int GetNumberOfKeyframeTracks() const
{
return NodeValue::get_number_of_keyframe_tracks(data_type_);
@@ -318,7 +327,7 @@ public:
*/
QVariant GetValueAtTime(const rational& time, int element = -1) const;
QVector<QVariant> GetSplitValuesAtTime(const rational& time, int element = -1) const;
SplitValue GetSplitValuesAtTime(const rational& time, int element = -1) const;
/**
* @brief Calculate the stored value for a specific track
@@ -378,13 +387,139 @@ protected:
virtual void childEvent(QChildEvent* e) override;
private:
void Init(Node *parent, const QString& id, NodeValue::Type type, const QVector<QVariant> &default_val);
class ArrayInsertCommand : public UndoCommand
{
public:
ArrayInsertCommand(NodeInput* input, int index) :
input_(input),
index_(index)
{
}
virtual Project* GetRelevantProject() const override;
virtual void redo() override
{
input_->ArrayInsert(index_, false);
}
virtual void undo() override
{
input_->ArrayRemove(index_, false);
}
private:
NodeInput* input_;
int index_;
};
class ArrayRemoveCommand : public UndoCommand
{
public:
ArrayRemoveCommand(NodeInput* input, int index) :
input_(input),
index_(index)
{
}
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override
{
// Save immediate data
is_keyframing_ = input_->IsKeyframing(index_);
standard_value_ = input_->GetSplitStandardValue(index_);
keyframes_ = input_->GetImmediate(index_)->keyframe_tracks();
input_->GetImmediate(index_)->delete_all_keyframes(&memory_manager_);
input_->ArrayRemove(index_, false);
}
virtual void undo() override
{
input_->ArrayInsert(index_, false);
// Restore keyframes
foreach (const NodeKeyframeTrack& track, keyframes_) {
foreach (NodeKeyframe* key, track) {
key->setParent(input_);
}
}
input_->SetSplitStandardValue(standard_value_, index_);
input_->SetIsKeyframing(is_keyframing_, index_);
}
private:
NodeInput* input_;
int index_;
SplitValue standard_value_;
bool is_keyframing_;
QVector<NodeKeyframeTrack> keyframes_;
QObject memory_manager_;
};
class ArrayResizeCommand : public UndoCommand
{
public:
ArrayResizeCommand(NodeInput* input, int size) :
input_(input),
size_(size)
{}
virtual void redo() override
{
old_size_ = input_->array_size_;
if (old_size_ > size_) {
// Decreasing in size, disconnect any extraneous edges
for (int i=size_; i<old_size_; i++) {
try {
Node* output = input_->edges().at(i);
removed_connections_.insert(i, output);
DisconnectEdge(output, input_, i);
} catch (std::out_of_range&) {}
}
}
input_->ArrayResizeInternal(size_);
}
virtual void undo() override
{
for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) {
ConnectEdge(it.value(), input_, it.key());
}
removed_connections_.clear();
input_->ArrayResizeInternal(old_size_);
}
virtual Project* GetRelevantProject() const override;
private:
NodeInput* input_;
int size_;
int old_size_;
QHash<int, Node*> removed_connections_;
};
void ClearElement(int index);
void Init(Node *parent, const QString& id, NodeValue::Type type, const SplitValue &default_val);
void LoadImmediate(QXmlStreamReader *reader, int element, XMLNodeData& xml_node_data, const QAtomicInt* cancelled);
void SaveImmediate(QXmlStreamWriter *writer, int element) const;
void ChangeArraySizeInternal(int size);
void ArrayResizeInternal(int size);
NodeInputImmediate* CreateImmediate();
@@ -426,7 +561,7 @@ private:
QVector<NodeInputImmediate*> subinputs_;
QVector<QVariant> default_value_;
SplitValue default_value_;
/**
* @brief Unique identifier of this input within this node
+4 -4
View File
@@ -106,21 +106,21 @@ void NodeInputDragger::End()
return;
}
QUndoCommand* command = new QUndoCommand();
MultiUndoCommand* command = new MultiUndoCommand();
if (input_->IsKeyframing(element_)) {
if (drag_created_key_) {
// We created a keyframe in this process
new NodeParamInsertKeyframeCommand(input_, dragging_key_, command);
command->add_child(new NodeParamInsertKeyframeCommand(input_, dragging_key_));
}
// We just set a keyframe's value
// We do this even when inserting a keyframe because we don't actually perform an insert in this undo command
// so this will ensure the ValueChanged() signal is sent correctly
new NodeParamSetKeyframeValueCommand(dragging_key_, end_value_, start_value_, command);
command->add_child(new NodeParamSetKeyframeValueCommand(dragging_key_, end_value_, start_value_));
} else {
// We just set the standard value
new NodeParamSetStandardValueCommand(input_, track_, element_, end_value_, start_value_, command);
command->add_child(new NodeParamSetStandardValueCommand(input_, track_, element_, end_value_, start_value_));
}
Core::instance()->undo_stack()->push(command);
+8 -4
View File
@@ -27,7 +27,7 @@
namespace olive {
NodeInputImmediate::NodeInputImmediate(NodeValue::Type type, const QVector<QVariant> &default_val) :
NodeInputImmediate::NodeInputImmediate(NodeValue::Type type, const SplitValue &default_val) :
keyframing_(false)
{
int track_size = NodeValue::get_number_of_keyframe_tracks(type);
@@ -43,7 +43,7 @@ void NodeInputImmediate::set_standard_value_on_track(const QVariant &value, int
standard_value_.replace(track, value);
}
void NodeInputImmediate::set_split_standard_value(const QVector<QVariant> &value)
void NodeInputImmediate::set_split_standard_value(const SplitValue &value)
{
for (int i=0; i<value.size() && i<standard_value_.size(); i++) {
standard_value_[i] = value[i];
@@ -267,11 +267,15 @@ void NodeInputImmediate::remove_keyframe(NodeKeyframe *key)
keyframe_tracks_[key->track()].removeOne(key);
}
void NodeInputImmediate::delete_all_keyframes()
void NodeInputImmediate::delete_all_keyframes(QObject* parent)
{
for (NodeKeyframeTrack& track : keyframe_tracks_) {
while (!track.isEmpty()) {
delete track.first();
if (parent) {
track.first()->setParent(parent);
} else {
delete track.first();
}
}
}
}
+6 -5
View File
@@ -25,6 +25,7 @@
#include "common/xmlutils.h"
#include "node/keyframe.h"
#include "node/value.h"
#include "splitvalue.h"
namespace olive {
@@ -33,7 +34,7 @@ class NodeInput;
class NodeInputImmediate
{
public:
NodeInputImmediate(NodeValue::Type type, const QVector<QVariant>& default_val);
NodeInputImmediate(NodeValue::Type type, const SplitValue& default_val);
/**
* @brief Internal insert function, automatically does an insertion sort based on the keyframe's time
@@ -42,19 +43,19 @@ public:
void remove_keyframe(NodeKeyframe* key);
void delete_all_keyframes();
void delete_all_keyframes(QObject *parent = nullptr);
/**
* @brief Get non-keyframed value split into components (the way it's stored)
*/
const QVector<QVariant>& get_split_standard_value() const
const SplitValue& get_split_standard_value() const
{
return standard_value_;
}
void set_standard_value_on_track(const QVariant &value, int track = 0);
void set_split_standard_value(const QVector<QVariant>& value);
void set_split_standard_value(const SplitValue& value);
/**
* @brief Retrieve a list of keyframe objects for all tracks at a given time
@@ -149,7 +150,7 @@ private:
/**
* @brief Non-keyframed value
*/
QVector<QVariant> standard_value_;
SplitValue standard_value_;
/**
* @brief Internal keyframe array
+7 -2
View File
@@ -45,14 +45,19 @@ NodeKeyframe::~NodeKeyframe()
setParent(nullptr);
}
NodeKeyframe *NodeKeyframe::copy(QObject* parent) const
NodeKeyframe *NodeKeyframe::copy(int element, QObject *parent) const
{
NodeKeyframe* copy = new NodeKeyframe(time_, value_, type_, track_, element_, parent);
NodeKeyframe* copy = new NodeKeyframe(time_, value_, type_, track_, element, parent);
copy->bezier_control_in_ = bezier_control_in_;
copy->bezier_control_out_ = bezier_control_out_;
return copy;
}
NodeKeyframe *NodeKeyframe::copy(QObject* parent) const
{
return copy(element_, parent);
}
NodeInput *NodeKeyframe::parent() const
{
return static_cast<NodeInput*>(QObject::parent());
+1
View File
@@ -65,6 +65,7 @@ public:
virtual ~NodeKeyframe() override;
NodeKeyframe* copy(int element, QObject* parent = nullptr) const;
NodeKeyframe* copy(QObject* parent = nullptr) const;
NodeInput* parent() const;
+4 -4
View File
@@ -247,7 +247,7 @@ TimeRange Node::OutputTimeAdjustment(NodeInput *, int, const TimeRange &input_ti
return input_time;
}
QVector<Node *> Node::CopyDependencyGraph(const QVector<Node *> &nodes, QUndoCommand* command)
QVector<Node *> Node::CopyDependencyGraph(const QVector<Node *> &nodes, MultiUndoCommand *command)
{
int nb_nodes = nodes.size();
@@ -263,7 +263,7 @@ QVector<Node *> Node::CopyDependencyGraph(const QVector<Node *> &nodes, QUndoCom
// Add to graph
NodeGraph* graph = static_cast<NodeGraph*>(nodes.at(i)->parent());
if (command) {
new NodeAddCommand(graph, c, command);
command->add_child(new NodeAddCommand(graph, c));
} else {
c->setParent(graph);
}
@@ -277,7 +277,7 @@ QVector<Node *> Node::CopyDependencyGraph(const QVector<Node *> &nodes, QUndoCom
return copies;
}
void Node::CopyDependencyGraph(const QVector<Node *> &src, const QVector<Node *> &dst, QUndoCommand *command)
void Node::CopyDependencyGraph(const QVector<Node *> &src, const QVector<Node *> &dst, MultiUndoCommand *command)
{
for (int i=0; i<src.size(); i++) {
foreach (NodeInput* input, src.at(i)->inputs()) {
@@ -290,7 +290,7 @@ void Node::CopyDependencyGraph(const QVector<Node *> &src, const QVector<Node *>
NodeInput* dst_input = dst.at(i)->GetInputWithID(input->id());
if (command) {
new NodeEdgeAddCommand(dst_output, dst_input, it->first, command);
command->add_child(new NodeEdgeAddCommand(dst_output, dst_input, it->first));
} else {
ConnectEdge(dst_output, dst_input, it->first);
}
+2 -2
View File
@@ -368,8 +368,8 @@ public:
/**
* @brief Clones a set of nodes and connects the new ones the way the old ones were
*/
static QVector<Node*> CopyDependencyGraph(const QVector<Node*>& nodes, QUndoCommand *command);
static void CopyDependencyGraph(const QVector<Node*>& src, const QVector<Node*>& dst, QUndoCommand *command);
static QVector<Node*> CopyDependencyGraph(const QVector<Node*>& nodes, MultiUndoCommand *command);
static void CopyDependencyGraph(const QVector<Node*>& src, const QVector<Node*>& dst, MultiUndoCommand *command);
/**
* @brief Return whether this Node can be deleted or not
+2 -2
View File
@@ -56,7 +56,7 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector<Node *> &nodes, vo
Core::CopyStringToClipboard(copy_str);
}
QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph, QUndoCommand* command, void *userdata)
QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph, MultiUndoCommand* command, void *userdata)
{
QString clipboard = Core::PasteStringFromClipboard();
@@ -121,7 +121,7 @@ QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph,
// Add all nodes to graph
foreach (Node* n, pasted_nodes) {
new NodeAddCommand(graph, n, command);
command->add_child(new NodeAddCommand(graph, n));
}
// Make connections
+1 -1
View File
@@ -37,7 +37,7 @@ public:
protected:
void CopyNodesToClipboard(const QVector<Node *> &nodes, void* userdata = nullptr);
QVector<Node*> PasteNodesFromClipboard(NodeGraph *graph, QUndoCommand *command, void* userdata = nullptr);
QVector<Node*> PasteNodesFromClipboard(NodeGraph *graph, MultiUndoCommand *command, void* userdata = nullptr);
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata);
+33
View File
@@ -0,0 +1,33 @@
/***
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 SPLITVALUE_H
#define SPLITVALUE_H
#include <QVariant>
#include <QVector>
namespace olive {
using SplitValue = QVector<QVariant>;
}
#endif // SPLITVALUE_H