@@ -89,6 +89,7 @@ void Config::SetDefaults()
|
||||
SetEntryInternal(QStringLiteral("RectifiedWaveforms"), NodeParam::kBoolean, false);
|
||||
SetEntryInternal(QStringLiteral("DropWithoutSequenceBehavior"), NodeParam::kInt, ImportTool::kDWSAsk);
|
||||
SetEntryInternal(QStringLiteral("Loop"), NodeParam::kBoolean, false);
|
||||
SetEntryInternal(QStringLiteral("SplitClipsCopyNodes"), NodeParam::kBoolean, true);
|
||||
|
||||
SetEntryInternal(QStringLiteral("AutoCacheInterval"), NodeParam::kInt, 250);
|
||||
|
||||
|
||||
@@ -99,6 +99,11 @@ PreferencesBehaviorTab::PreferencesBehaviorTab()
|
||||
AddItem(tr("Auto-Scale By Default"),
|
||||
QStringLiteral("AutoscaleByDefault"),
|
||||
node_group);
|
||||
AddItem(tr("Splitting Clips Copies Dependencies"),
|
||||
QStringLiteral("SplitClipsCopyNodes"),
|
||||
tr("Multiple clips can share the same nodes. Disable this to automatically share node "
|
||||
"dependencies among clips when copying or splitting them."),
|
||||
node_group);
|
||||
}
|
||||
|
||||
void PreferencesBehaviorTab::Accept()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "project/project.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/item/footage/videostream.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -239,6 +240,66 @@ TimeRange Node::OutputTimeAdjustment(NodeInput *, const TimeRange &input_time) c
|
||||
return input_time;
|
||||
}
|
||||
|
||||
QVector<Node *> Node::CopyDependencyGraph(const QVector<Node *> &nodes, QUndoCommand* command)
|
||||
{
|
||||
int nb_nodes = nodes.size();
|
||||
|
||||
QVector<Node*> copies(nb_nodes);
|
||||
|
||||
for (int i=0; i<nb_nodes; i++) {
|
||||
// Create another of the same node
|
||||
Node* c = nodes.at(i)->copy();;
|
||||
|
||||
// Copy the values, but NOT the connections, since we'll be connecting to our own clones later
|
||||
Node::CopyInputs(nodes.at(i), c, false);
|
||||
|
||||
// Add to graph
|
||||
NodeGraph* graph = static_cast<NodeGraph*>(nodes.at(i)->parent());
|
||||
if (command) {
|
||||
new NodeAddCommand(graph, c, command);
|
||||
} else {
|
||||
graph->AddNode(c);
|
||||
}
|
||||
|
||||
// Store in array at the same index as source
|
||||
copies[i] = c;
|
||||
}
|
||||
|
||||
CopyDependencyGraph(nodes, copies, command);
|
||||
|
||||
return copies;
|
||||
}
|
||||
|
||||
void Node::CopyDependencyGraph(const QVector<Node *> &src, const QVector<Node *> &dst, QUndoCommand *command)
|
||||
{
|
||||
int nb_nodes = src.size();
|
||||
|
||||
for (int i=0; i<nb_nodes; i++) {
|
||||
// Find any interconnections
|
||||
QVector<NodeInput*> inputs = src.at(i)->GetInputsIncludingArrays();
|
||||
|
||||
for (int j=0; j<nb_nodes; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (NodeInput* input, inputs) {
|
||||
if (input->get_connected_node() == src.at(j)) {
|
||||
// Found a connection
|
||||
NodeOutput* copy_output = dst.at(j)->GetOutputWithID(input->get_connected_output()->id());
|
||||
NodeInput* copy_input = dst.at(i)->GetInputWithID(input->id());
|
||||
|
||||
if (command) {
|
||||
new NodeEdgeAddCommand(copy_output, copy_input, command);
|
||||
} else {
|
||||
NodeParam::ConnectEdge(copy_output, copy_input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::SendInvalidateCache(const TimeRange &range, NodeInput *source)
|
||||
{
|
||||
// Loop through all parameters (there should be no children that are not NodeParams)
|
||||
|
||||
@@ -346,6 +346,12 @@ public:
|
||||
*/
|
||||
static void CopyInputs(Node* source, Node* destination, bool include_connections = true);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Return whether this Node can be deleted or not
|
||||
*/
|
||||
|
||||
@@ -288,43 +288,11 @@ void NodeView::Duplicate()
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
QList<Node*> duplicated_nodes;
|
||||
|
||||
foreach (Node* n, selected) {
|
||||
Node* copy = n->copy();
|
||||
|
||||
Node::CopyInputs(n, copy, false);
|
||||
|
||||
duplicated_nodes.append(copy);
|
||||
|
||||
new NodeAddCommand(graph_, copy, command);
|
||||
}
|
||||
|
||||
for (int i=0;i<selected.size();i++) {
|
||||
Node* src = selected.at(i);
|
||||
|
||||
for (int j=0;j<selected.size();j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Node* dst = selected.at(j);
|
||||
|
||||
foreach (NodeEdgePtr edge, src->output()->edges()) {
|
||||
if (edge->input()->parentNode() == dst) {
|
||||
new NodeEdgeAddCommand(duplicated_nodes.at(i)->output(),
|
||||
duplicated_nodes.at(j)->GetInputWithID(edge->input()->id()),
|
||||
command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QVector<Node*> duplicated_nodes = Node::CopyDependencyGraph(selected, command);
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
|
||||
if (!duplicated_nodes.isEmpty()) {
|
||||
AttachNodesToCursor(duplicated_nodes);
|
||||
}
|
||||
AttachNodesToCursor(duplicated_nodes);
|
||||
}
|
||||
|
||||
void NodeView::ItemsChanged()
|
||||
|
||||
@@ -610,13 +610,23 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
|
||||
|
||||
if (duplicate_clips) {
|
||||
// Duplicate rather than move
|
||||
Node* copy = block->copy();
|
||||
Node* copy;
|
||||
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(block->parent()),
|
||||
copy,
|
||||
command);
|
||||
if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) {
|
||||
QVector<Node*> nodes_to_clone;
|
||||
nodes_to_clone.append(block);
|
||||
nodes_to_clone.append(block->GetDependencies());
|
||||
QVector<Node*> duplicated = Node::CopyDependencyGraph(nodes_to_clone, command);
|
||||
copy = duplicated.first();
|
||||
} else {
|
||||
copy = block->copy();
|
||||
|
||||
new NodeCopyInputsCommand(block, copy, true, command);
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(block->parent()),
|
||||
copy,
|
||||
command);
|
||||
|
||||
new NodeCopyInputsCommand(block, copy, true, command);
|
||||
}
|
||||
|
||||
// Place the copy instead of the original block
|
||||
block = static_cast<Block*>(copy);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "undo.h"
|
||||
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
#include "node/block/clip/clip.h"
|
||||
#include "node/block/transition/transition.h"
|
||||
@@ -209,10 +210,21 @@ void TrackRippleRemoveAreaCommand::redo_internal()
|
||||
if (splice_) {
|
||||
|
||||
// Split the block here
|
||||
trim_in_ = static_cast<Block*>(trim_out_->copy());
|
||||
splice_split_command_ = new QUndoCommand();
|
||||
|
||||
static_cast<NodeGraph*>(track_->parent())->AddNode(trim_in_);
|
||||
Node::CopyInputs(trim_out_, trim_in_);
|
||||
if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) {
|
||||
QVector<Node*> nodes_to_clone;
|
||||
nodes_to_clone.append(trim_out_);
|
||||
nodes_to_clone.append(trim_out_->GetDependencies());
|
||||
QVector<Node*> duplicated = Node::CopyDependencyGraph(nodes_to_clone, splice_split_command_);
|
||||
trim_in_ = static_cast<Block*>(duplicated.first());
|
||||
} else {
|
||||
trim_in_ = static_cast<Block*>(trim_out_->copy());
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(track_->parent()), trim_in_, splice_split_command_);
|
||||
new NodeCopyInputsCommand(trim_out_, trim_in_, true, splice_split_command_);
|
||||
}
|
||||
|
||||
splice_split_command_->redo();
|
||||
|
||||
trim_out_old_length_ = trim_out_->length();
|
||||
trim_out_->set_length_and_media_out(in_ - trim_out_->in());
|
||||
@@ -292,7 +304,8 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
||||
track_->RippleRemoveBlock(trim_in_);
|
||||
trim_out_->set_length_and_media_out(trim_out_old_length_);
|
||||
|
||||
TakeNodeFromParentGraph(trim_in_, &memory_manager_);
|
||||
splice_split_command_->undo();
|
||||
delete splice_split_command_;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -428,8 +441,33 @@ void BlockSplitCommand::redo_internal()
|
||||
{
|
||||
track_->BeginOperation();
|
||||
|
||||
static_cast<NodeGraph*>(block_->parent())->AddNode(new_block_);
|
||||
Node::CopyInputs(block_, new_block_);
|
||||
NodeGraph* graph = static_cast<NodeGraph*>(block_->parent());
|
||||
|
||||
add_command_ = new QUndoCommand();
|
||||
new NodeAddCommand(graph, new_block_, add_command_);
|
||||
new NodeCopyInputsCommand(block_, new_block_, true, add_command_);
|
||||
|
||||
if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) {
|
||||
|
||||
QVector<Node*> src_nodes;
|
||||
QVector<Node*> dst_nodes;
|
||||
|
||||
src_nodes.append(block_);
|
||||
src_nodes.append(block_->GetDependencies());
|
||||
|
||||
dst_nodes.resize(src_nodes.size());
|
||||
dst_nodes[0] = new_block_;
|
||||
for (int i=1; i<dst_nodes.size(); i++) {
|
||||
dst_nodes[i] = src_nodes[i]->copy();
|
||||
new NodeAddCommand(graph, dst_nodes[i], add_command_);
|
||||
Node::CopyInputs(src_nodes[i], dst_nodes[i], false);
|
||||
}
|
||||
|
||||
Node::CopyDependencyGraph(src_nodes, dst_nodes, add_command_);
|
||||
|
||||
}
|
||||
|
||||
add_command_->redo();
|
||||
|
||||
rational new_part_length = block_->length() - (point_ - block_->in());
|
||||
|
||||
@@ -451,16 +489,18 @@ void BlockSplitCommand::undo_internal()
|
||||
{
|
||||
track_->BeginOperation();
|
||||
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
track_->RippleRemoveBlock(new_block_);
|
||||
|
||||
TakeNodeFromParentGraph(new_block_, &memory_manager_);
|
||||
|
||||
foreach (NodeInput* transition, transitions_to_move_) {
|
||||
NodeParam::DisconnectEdge(new_block_->output(), transition);
|
||||
NodeParam::ConnectEdge(block_->output(), transition);
|
||||
}
|
||||
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
track_->RippleRemoveBlock(new_block_);
|
||||
|
||||
add_command_->undo();
|
||||
new_block_->setParent(&memory_manager_);
|
||||
delete add_command_;
|
||||
|
||||
track_->EndOperation();
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +192,7 @@ protected:
|
||||
rational out_;
|
||||
|
||||
bool splice_;
|
||||
QUndoCommand* splice_split_command_;
|
||||
|
||||
Block* trim_out_;
|
||||
Block* trim_in_;
|
||||
@@ -329,17 +330,18 @@ protected:
|
||||
private:
|
||||
TrackOutput* track_;
|
||||
Block* block_;
|
||||
Block* new_block_;
|
||||
|
||||
rational new_length_;
|
||||
rational old_length_;
|
||||
rational point_;
|
||||
|
||||
Block* new_block_;
|
||||
|
||||
QList<NodeInput*> transitions_to_move_;
|
||||
|
||||
QObject memory_manager_;
|
||||
|
||||
QUndoCommand* add_command_;
|
||||
|
||||
};
|
||||
|
||||
class TrackSplitAtTimeCommand : public UndoCommand {
|
||||
|
||||
Reference in New Issue
Block a user