diff --git a/app/core.cpp b/app/core.cpp index 48830651a..82a6b98fc 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -437,7 +437,7 @@ void Core::CreateNewSequence() command->add_child(new NodeAddCommand(active_project, new_sequence)); command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence)); - command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false)); + command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0))); // Create and connect default nodes to new sequence new_sequence->add_default_nodes(command); diff --git a/app/node/graph.cpp b/app/node/graph.cpp index a2d04b233..f652340fb 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -44,45 +44,6 @@ void NodeGraph::Clear() } } -qreal NodeGraph::GetNodeContextHeight(Node *context) -{ - const PositionMap &map = position_map_.value(context); - - qreal top = 0, bottom = 0; - - foreach (const QPointF &pt, map) { - top = qMin(pt.y(), top); - bottom = qMax(pt.y(), bottom); - } - - return bottom - top; -} - -int NodeGraph::GetNumberOfContextsNodeIsIn(Node *node) const -{ - int count = 0; - - for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) { - if (it.value().contains(node)) { - count++; - } - } - - return count; -} - -bool NodeGraph::NodeOutputsToContext(Node *node) const -{ - for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) { - const PositionMap &pm = it.value(); - if (pm.contains(node) && node->OutputsTo(it.key(), true)) { - return true; - } - } - - return false; -} - void NodeGraph::childEvent(QChildEvent *event) { super::childEvent(event); @@ -116,18 +77,10 @@ void NodeGraph::childEvent(QChildEvent *event) emit NodeRemoved(node); emit node->RemovedFromGraph(this); - for (auto it=position_map_.begin(); it!=position_map_.end(); it++) { - PositionMap &map = it.value(); - for (auto jt=map.begin(); jt!=map.end(); ) { - if (jt.key() == node) { - jt = map.erase(jt); - emit NodePositionRemoved(node, it.key()); - } else { - jt++; - } - } + // Remove from any contexts + foreach (Node *context, node_children_) { + context->RemoveNodeFromContext(node); } - } } } diff --git a/app/node/graph.h b/app/node/graph.h index 5e0aa5be2..21c8f023e 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -63,55 +63,6 @@ public: return default_nodes_; } - bool NodeMapContainsNode(Node* node, Node* context) const - { - return position_map_.value(context).contains(node); - } - - QPointF GetNodePosition(Node* node, Node* context) - { - return position_map_.value(context).value(node); - } - - void SetNodePosition(Node* node, Node* context, const QPointF& pos) - { - position_map_[context].insert(node, pos); - emit NodePositionAdded(node, context, pos); - } - - void RemoveNodePosition(Node* node, Node* context) - { - PositionMap& map = position_map_[context]; - map.remove(node); - if (map.isEmpty()) { - position_map_.remove(context); - } - emit NodePositionRemoved(node, context); - } - - bool ContextContainsNode(Node *node, Node *context) - { - return position_map_[context].contains(node); - } - - qreal GetNodeContextHeight(Node *context); - - using PositionMap = QHash; - - const PositionMap &GetNodesForContext(Node *context) - { - return position_map_[context]; - } - - const QMap &GetPositionMap() const - { - return position_map_; - } - - int GetNumberOfContextsNodeIsIn(Node *node) const; - - bool NodeOutputsToContext(Node *node) const; - signals: /** * @brief Signal emitted when a Node is added to the graph @@ -148,10 +99,6 @@ private: QVector default_nodes_; - QMap position_map_; - - PositionMap root_position_map_; - }; } diff --git a/app/node/node.cpp b/app/node/node.cpp index d79710962..b1b45ccf6 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -243,6 +243,36 @@ QIcon Node::icon() const return icon::New; } +QPointF Node::GetNodePositionInContext(Node *node) +{ + return context_positions_.value(node); +} + +bool Node::SetNodePositionInContext(Node *node, const QPointF &pos) +{ + bool added = !ContextContainsNode(node); + context_positions_.insert(node, pos); + + if (added) { + emit NodeAddedToContext(node); + } + + emit NodePositionInContextChanged(node, pos); + + return added; +} + +bool Node::RemoveNodeFromContext(Node *node) +{ + if (ContextContainsNode(node)) { + context_positions_.remove(node); + emit NodeRemovedFromContext(node); + return true; + } else { + return false; + } +} + Color Node::color() const { int c; @@ -429,6 +459,11 @@ void Node::SaveInput(QXmlStreamWriter *writer, const QString &id) const writer->writeEndElement(); // subelements } +bool Node::IsInputHidden(const QString &input) const +{ + return (GetInputFlags(input) & kInputFlagHidden); +} + bool Node::IsInputConnectable(const QString &input) const { return !(GetInputFlags(input) & kInputFlagNotConnectable); @@ -1196,13 +1231,10 @@ Node *Node::CopyNodeAndDependencyGraphMinusItemsInternal(QMap& cre command->add_child(new NodeSetValueHintCommand(copied_input, node->GetValueHintForInput(input.input(), input.element()))); } - if (node->parent()->GetPositionMap().contains(node)) { - // This node is a context, copy the context - const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node); - for (auto it=map.cbegin(); it!=map.cend(); it++) { - // Add either the copy (if it exists) or the original node to the context - command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value(), false)); - } + const PositionMap &map = node->GetContextPositions(); + for (auto it=map.cbegin(); it!=map.cend(); it++) { + // Add either the copy (if it exists) or the original node to the context + command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value())); } return copy; @@ -1229,13 +1261,10 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command) command->add_child(new NodeCopyInputsCommand(node, copy, true)); - if (node->parent()->GetPositionMap().contains(node)) { - // This node is a context, copy the context - const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node); - for (auto it=map.cbegin(); it!=map.cend(); it++) { - // Add to the context - command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value(), false)); - } + const PositionMap &map = node->GetContextPositions(); + for (auto it=map.cbegin(); it!=map.cend(); it++) { + // Add to the context + command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value())); } } @@ -2318,119 +2347,58 @@ Project *Node::ArrayResizeCommand::GetRelevantProject() const return node_->project(); } -void NodeSetPositionAndShiftSurroundingsCommand::redo() -{ - if (commands_.isEmpty()) { - // Move first node - NodeSetPositionCommand* set_pos_command = new NodeSetPositionCommand(node_, relative_, position_, move_dependencies_); - set_pos_command->redo_now(); - commands_.append(set_pos_command); - - // Get bounding rect - qreal bounding_rect_sz = 1.0; - qreal bounding_rect_half_sz = bounding_rect_sz * 0.5; - QRectF bounding_rect(position_.x() - bounding_rect_half_sz, position_.y() - bounding_rect_half_sz, bounding_rect_sz, bounding_rect_sz); - - // Start moving other nodes - foreach (Node* surrounding, node_->parent()->nodes()) { - if (surrounding != node_) { - QPointF surrounding_position = node_->parent()->GetNodePosition(surrounding, relative_); - if (bounding_rect.contains(surrounding_position)) { - QPointF new_pos = surrounding_position; - - qreal move_rate = 0.50; - - if (surrounding_position.y() < position_.y()) { - move_rate = -move_rate; - } - - new_pos.setY(new_pos.y() + move_rate); - - auto sur_command = new NodeSetPositionAndShiftSurroundingsCommand(surrounding, relative_, new_pos, true); - sur_command->redo(); - commands_.append(sur_command); - } - } - } - } else { - for (int i=0; iredo_now(); - } - } -} - void NodeSetPositionCommand::redo() { - graph_ = node_->parent(); - if (!(added_ = !graph_->NodeMapContainsNode(node_, relevant_))) { - old_pos_ = graph_->GetNodePosition(node_, relevant_); + if (!(added_ = !context_->ContextContainsNode(node_))) { + old_pos_ = context_->GetNodePositionInContext(node_); + } + + if (added_) { + context_->SetNodePositionInContext(node_, pos_); + } else { + move(context_, node_, pos_ - old_pos_, move_deps_); } - graph_->SetNodePosition(node_, relevant_, pos_); } void NodeSetPositionCommand::undo() { if (added_) { - graph_->RemoveNodePosition(node_, relevant_); + context_->RemoveNodeFromContext(node_); } else { - graph_->SetNodePosition(node_, relevant_, old_pos_); + move(context_, node_, old_pos_ - pos_, move_deps_); } } -void NodeSetPositionAsChildCommand::redo() +void NodeSetPositionCommand::move(Node *context, Node *node, const QPointF &diff, bool recursive) { - if (!sub_command_) { - // Calculate position of node - NodeGraph *graph = parent_->parent(); - QPointF pos = graph->GetNodePosition(parent_, relative_); + QPointF p = context->GetNodePositionInContext(node); + p += diff; + context->SetNodePositionInContext(node, p); - // This is a dependency, so we'll place it one X before - pos.setX(pos.x() - 1); - - // The Y will be calculated using the index and child count - pos.setY(pos.y() - (double(child_count_)*0.5) + this_index_ + 0.5); - - sub_command_ = new MultiUndoCommand(); - if (shift_surroundings_) { - sub_command_->add_child(new NodeSetPositionAndShiftSurroundingsCommand(node_, relative_, pos, true)); - } else { - sub_command_->add_child(new NodeSetPositionCommand(node_, relative_, pos, true)); + if (recursive) { + for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { + Node *output = it->second; + if (context->ContextContainsNode(output)) { + move(context, output, diff, recursive); + } } } - - sub_command_->redo_now(); -} - -void NodeSetPositionToOffsetOfAnotherNodeCommand::redo() -{ - NodeGraph *graph = node_->parent(); - old_pos_ = graph->GetNodePosition(node_, relative_); - graph->SetNodePosition(node_, relative_, graph->GetNodePosition(other_node_, relative_) + offset_); -} - -void NodeSetPositionToOffsetOfAnotherNodeCommand::undo() -{ - NodeGraph *graph = node_->parent(); - graph->SetNodePosition(node_, relative_, old_pos_); } void NodeRemovePositionFromContextCommand::redo() { - NodeGraph *graph = node_->parent(); - - contained_ = graph->ContextContainsNode(node_, context_); + contained_ = context_->ContextContainsNode(node_); if (contained_) { - old_pos_ = graph->GetNodePosition(node_, context_); - graph->RemoveNodePosition(node_, context_); + old_pos_ = context_->GetNodePositionInContext(node_); + context_->RemoveNodeFromContext(node_); } } void NodeRemovePositionFromContextCommand::undo() { if (contained_) { - NodeGraph *graph = node_->parent(); - graph->SetNodePosition(node_, context_, old_pos_); + context_->SetNodePositionInContext(node_, old_pos_); } } @@ -2438,28 +2406,21 @@ void NodeRemovePositionFromAllContextsCommand::redo() { NodeGraph *graph = node_->parent(); - if (points_.empty()) { - // No points yet, let's see what points we should remove - auto map = graph->GetPositionMap(); - for (auto it=map.cbegin(); it!=map.cend(); it++) { - if (it.value().contains(node_)) { - points_.insert({it.key(), it.value().value(node_)}); - } + foreach (Node* context, graph->nodes()) { + if (context->ContextContainsNode(node_)) { + contexts_.insert({context, context->GetNodePositionInContext(node_)}); + context->RemoveNodeFromContext(node_); } } - - for (auto it=points_.cbegin(); it!=points_.cend(); it++) { - graph->RemoveNodePosition(node_, it->first); - } } void NodeRemovePositionFromAllContextsCommand::undo() { - NodeGraph *graph = node_->parent(); - - for (auto it=points_.crbegin(); it!=points_.crend(); it++) { - graph->SetNodePosition(node_, it->first, it->second); + for (auto it = contexts_.crbegin(); it != contexts_.crend(); it++) { + it->first->SetNodePositionInContext(node_, it->second); } + + contexts_.clear(); } void Node::ValueHint::Hash(QCryptographicHash &hash) const diff --git a/app/node/node.h b/app/node/node.h index b22af3fff..fceb08d1c 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -208,6 +208,23 @@ public: return HasInputWithID(id); } + using PositionMap = QHash; + const PositionMap &GetContextPositions() const + { + return context_positions_; + } + + bool ContextContainsNode(Node *node) const + { + return context_positions_.contains(node); + } + + QPointF GetNodePositionInContext(Node *node); + + bool SetNodePositionInContext(Node *node, const QPointF &pos); + + bool RemoveNodeFromContext(Node *node); + /** * @brief Retrieve the color of this node */ @@ -248,6 +265,7 @@ public: void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled); void SaveInput(QXmlStreamWriter* writer, const QString& id) const; + bool IsInputHidden(const QString& input) const; bool IsInputConnectable(const QString& input) const; bool IsInputKeyframable(const QString& input) const; @@ -867,7 +885,8 @@ protected: kInputFlagNormal = 0x0, kInputFlagArray = 0x1, kInputFlagNotKeyframable = 0x2, - kInputFlagNotConnectable = 0x4 + kInputFlagNotConnectable = 0x4, + kInputFlagHidden = 0x8 }; class InputFlags { @@ -1037,6 +1056,12 @@ signals: void RemovedFromGraph(NodeGraph* graph); + void NodeAddedToContext(Node *node); + + void NodePositionInContextChanged(Node *node, const QPointF &pos); + + void NodeRemovedFromContext(Node *node); + private: class ArrayInsertCommand : public UndoCommand { @@ -1258,6 +1283,8 @@ private: QMap value_hints_; + PositionMap context_positions_; + private slots: /** * @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time @@ -1367,10 +1394,10 @@ using NodePtr = std::shared_ptr; class NodeSetPositionCommand : public UndoCommand { public: - NodeSetPositionCommand(Node* node, Node* relevant, const QPointF& pos, bool move_dependencies_relatively) + NodeSetPositionCommand(Node* node, Node* context, const QPointF& pos, bool move_dependencies_relatively = false) { node_ = node; - relevant_ = relevant; + context_ = context; pos_ = pos; move_deps_ = move_dependencies_relatively; } @@ -1386,151 +1413,14 @@ protected: virtual void undo() override; private: + static void move(Node *context, Node *node, const QPointF &diff, bool recursive); + Node* node_; - Node* relevant_; + Node* context_; QPointF pos_; QPointF old_pos_; bool added_; bool move_deps_; - NodeGraph *graph_; - -}; - -class NodeSetPositionAndShiftSurroundingsCommand : public UndoCommand -{ -public: - NodeSetPositionAndShiftSurroundingsCommand(Node* node, Node *relative, const QPointF& pos, bool move_dependencies_relatively) : - node_(node), - relative_(relative), - position_(pos), - move_dependencies_(move_dependencies_relatively) - {} - - virtual ~NodeSetPositionAndShiftSurroundingsCommand() override - { - qDeleteAll(commands_); - } - - virtual Project * GetRelevantProject() const override - { - return node_->project(); - } - -protected: - virtual void redo() override; - - virtual void undo() override - { - for (int i=commands_.size()-1; i>=0; i--) { - commands_.at(i)->undo_now(); - } - } - -private: - Node* node_; - - Node *relative_; - - QPointF position_; - - bool move_dependencies_; - - QVector commands_; - -}; - -class NodeSetPositionAsChildCommand : public UndoCommand -{ -public: - NodeSetPositionAsChildCommand(Node* node, Node* parent, Node *relative, double this_index, int child_count, bool shift_surroundings) : - node_(node), - parent_(parent), - relative_(relative), - this_index_(this_index), - child_count_(child_count), - shift_surroundings_(shift_surroundings), - sub_command_(nullptr) - { - } - - virtual ~NodeSetPositionAsChildCommand() override - { - delete sub_command_; - } - - virtual Project * GetRelevantProject() const override - { - return node_->project(); - } - -protected: - virtual void redo() override; - - virtual void undo() override - { - sub_command_->undo_now(); - } - -private: - Node* node_; - Node* parent_; - Node *relative_; - - double this_index_; - int child_count_; - - bool shift_surroundings_; - - MultiUndoCommand* sub_command_; - -}; - -class NodePositionCloseChildGapCommand : public UndoCommand -{ -public: - NodePositionCloseChildGapCommand(Node *parent, void *relative, int remove_index, int child_count, bool shift_surroundings); - - virtual Project * GetRelevantProject() const override - { - return parent_->project(); - } - -protected: - virtual void redo() override; - - virtual void undo() override; - -private: - Node *parent_; - -}; - -class NodeSetPositionToOffsetOfAnotherNodeCommand : public UndoCommand -{ -public: - NodeSetPositionToOffsetOfAnotherNodeCommand(Node* node, Node* other_node, Node *relative, const QPointF& offset) : - node_(node), - other_node_(other_node), - relative_(relative), - offset_(offset) - {} - - virtual Project * GetRelevantProject() const override - { - return node_->project(); - } - -protected: - virtual void redo() override; - - virtual void undo() override; - -private: - Node* node_; - Node* other_node_; - Node *relative_; - QPointF offset_; - QPointF old_pos_; }; @@ -1585,7 +1475,7 @@ protected: private: Node *node_; - std::map points_; + std::map contexts_; }; diff --git a/app/node/nodecopypaste.cpp b/app/node/nodecopypaste.cpp index 2d66d72ae..0de513820 100644 --- a/app/node/nodecopypaste.cpp +++ b/app/node/nodecopypaste.cpp @@ -53,11 +53,11 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector &nodes, vo writer.writeStartElement(QStringLiteral("contexts")); foreach (Node* n, nodes) { // Determine if this node is a context - if (n->parent()->GetPositionMap().contains(n)) { + if (!n->GetContextPositions().isEmpty()) { writer.writeStartElement(QStringLiteral("context")); writer.writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(n))); - const NodeGraph::PositionMap &map = n->parent()->GetNodesForContext(n); + const Node::PositionMap &map = n->GetContextPositions(); for (auto it=map.cbegin(); it!=map.cend(); it++) { writer.writeStartElement(QStringLiteral("node")); Project::SavePosition(&writer, it.key(), it.value()); @@ -220,7 +220,7 @@ QVector NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph, for (auto jt=map.cbegin(); jt!=map.cend(); jt++) { Node *subnode = xml_node_data.node_ptrs.value(jt.key()); if (subnode) { - command->add_child(new NodeSetPositionCommand(subnode, context, jt.value(), false)); + command->add_child(new NodeSetPositionCommand(subnode, context, jt.value())); } } } diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index e1cb208d6..9506f4513 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -44,7 +44,7 @@ Track::Track() : locked_(false), sequence_(nullptr) { - AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable)); + AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable | kInputFlagHidden)); // Since blocks are time based, we can handle the invalidate timing a little more intelligently // on our end diff --git a/app/node/param.cpp b/app/node/param.cpp index 9f6bd8c4d..f0a685abe 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -33,6 +33,15 @@ QString NodeInput::name() const } } +bool NodeInput::IsHidden() const +{ + if (IsValid()) { + return node_->IsInputHidden(input_); + } else { + return false; + } +} + bool NodeInput::IsConnected() const { if (IsValid()) { diff --git a/app/node/param.h b/app/node/param.h index 63aa413f7..3de4b6727 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -115,6 +115,8 @@ public: return node_ && !input_.isEmpty() && element_ >= -1; } + bool IsHidden() const; + bool IsConnected() const; bool IsKeyframing() const; diff --git a/app/node/project/folder/folder.cpp b/app/node/project/folder/folder.cpp index feae6d612..7b017923f 100644 --- a/app/node/project/folder/folder.cpp +++ b/app/node/project/folder/folder.cpp @@ -113,19 +113,12 @@ void Folder::InputDisconnectedEvent(const QString &input, int element, Node *out } } -FolderAddChild::FolderAddChild(Folder *folder, Node *child, bool autoposition) : +FolderAddChild::FolderAddChild(Folder *folder, Node *child) : folder_(folder), - child_(child), - autoposition_(autoposition), - position_command_(nullptr) + child_(child) { } -FolderAddChild::~FolderAddChild() -{ - delete position_command_; -} - Project *FolderAddChild::GetRelevantProject() const { return folder_->project(); @@ -136,21 +129,10 @@ void FolderAddChild::redo() int array_index = folder_->InputArraySize(Folder::kChildInput); folder_->InputArrayAppend(Folder::kChildInput, false); Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index)); - - if (autoposition_) { - if (!position_command_) { - position_command_ = new NodeSetPositionAsChildCommand(child_, folder_, folder_->project()->root(), array_index, array_index+1, true); - } - position_command_->redo_now(); - } } void FolderAddChild::undo() { - if (position_command_) { - position_command_->undo_now(); - } - Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1)); folder_->InputArrayRemoveLast(Folder::kChildInput); } diff --git a/app/node/project/folder/folder.h b/app/node/project/folder/folder.h index 1303ce7d7..12677e57b 100644 --- a/app/node/project/folder/folder.h +++ b/app/node/project/folder/folder.h @@ -208,9 +208,7 @@ private: class FolderAddChild : public UndoCommand { public: - FolderAddChild(Folder* folder, Node* child, bool autoposition = true); - - virtual ~FolderAddChild() override; + FolderAddChild(Folder* folder, Node* child); virtual Project * GetRelevantProject() const override; @@ -224,10 +222,6 @@ private: Node* child_; - bool autoposition_; - - NodeSetPositionAsChildCommand* position_command_; - }; } diff --git a/app/node/project/project.cpp b/app/node/project/project.cpp index f865e28c8..64d7cb107 100644 --- a/app/node/project/project.cpp +++ b/app/node/project/project.cpp @@ -44,19 +44,16 @@ Project::Project() : root_->setParent(this); root_->SetLabel(tr("Root")); root_->SetCanBeDeleted(false); - SetNodePosition(root_, root_, QPointF(0, 0)); // Adds a color manager "node" to this project so that it synchronizes color_manager_ = new ColorManager(); color_manager_->setParent(this); - SetNodePosition(color_manager_, root_, QPointF(1, 0)); color_manager_->SetCanBeDeleted(false); AddDefaultNode(color_manager_); // Same with project settings settings_ = new ProjectSettingsNode(); settings_->setParent(this); - SetNodePosition(settings_, root_, QPointF(2, 0)); settings_->SetCanBeDeleted(false); AddDefaultNode(settings_); @@ -167,7 +164,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint Node *node = xml_node_data.node_ptrs.value(node_ptr); if (node) { - SetNodePosition(node, context, node_pos); + context->SetNodePositionInContext(node, node_pos); } else { qWarning() << "Failed to find pointer for node position"; reader->skipCurrentElement(); @@ -230,20 +227,22 @@ void Project::Save(QXmlStreamWriter *writer) const writer->writeStartElement(QStringLiteral("positions")); - for (auto it=GetPositionMap().cbegin(); it!=GetPositionMap().cend(); it++) { - writer->writeStartElement(QStringLiteral("context")); + foreach (Node* context, nodes()) { + const Node::PositionMap &map = context->GetContextPositions(); - writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(it.key()))); + if (!map.isEmpty()) { + writer->writeStartElement(QStringLiteral("context")); - const PositionMap &map = it.value(); + writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(context))); - for (auto jt=map.cbegin(); jt!=map.cend(); jt++) { - writer->writeStartElement(QStringLiteral("node")); - SavePosition(writer, jt.key(), jt.value()); - writer->writeEndElement(); // node + for (auto jt=map.cbegin(); jt!=map.cend(); jt++) { + writer->writeStartElement(QStringLiteral("node")); + SavePosition(writer, jt.key(), jt.value()); + writer->writeEndElement(); // node + } + + writer->writeEndElement(); // context } - - writer->writeEndElement(); // context } writer->writeEndElement(); // positions diff --git a/app/node/project/sequence/sequence.cpp b/app/node/project/sequence/sequence.cpp index 27b17708f..0cb443188 100644 --- a/app/node/project/sequence/sequence.cpp +++ b/app/node/project/sequence/sequence.cpp @@ -41,7 +41,7 @@ Sequence::Sequence() // Create track input QString track_input_id = kTrackInputFormat.arg(i); - AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray)); + AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden)); IgnoreInvalidationsFrom(track_input_id); diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 591f7a867..3f0e3a4a2 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -38,6 +38,7 @@ NodePanel::NodePanel(QWidget *parent) : // Create NodeView widget node_view_ = new NodeView(this); outer_layout->addWidget(node_view_); + connect(this, &NodePanel::visibilityChanged, node_view_, &NodeView::CenterOnItemsBoundingRect); // Connect toolbar to NodeView connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled); diff --git a/app/panel/node/node.h b/app/panel/node/node.h index d145bb91d..20eccc79a 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -36,20 +36,15 @@ class NodePanel : public PanelWidget public: NodePanel(QWidget* parent); - NodeGraph* GetGraph() const + void SetContexts(const QVector &nodes) { - return node_view_->GetGraph(); + node_view_->SetContexts(nodes); + toolbar_->setEnabled(!nodes.isEmpty()); } - void SetGraph(NodeGraph *graph, const QVector &nodes) + void CloseContextsBelongingToProject(Project *project) { - node_view_->SetGraph(graph, nodes); - toolbar_->setEnabled(graph); - } - - void ClearGraph() - { - node_view_->ClearGraph(); + node_view_->CloseContextsBelongingToProject(project); } const QVector &GetCurrentContexts() const @@ -113,11 +108,6 @@ public slots: node_view_->Select(nodes, center_view_on_item); } - void SelectWithDependencies(const QVector& nodes, bool center_view_on_item) - { - node_view_->SelectWithDependencies(nodes, center_view_on_item); - } - signals: void NodesSelected(const QVector& nodes); diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 31be310c6..4c8385d9d 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -42,15 +42,13 @@ const double NodeView::kMinimumScale = 0.1; NodeView::NodeView(QWidget *parent) : HandMovableView(parent), - graph_(nullptr), drop_edge_(nullptr), create_edge_(nullptr), create_edge_dst_(nullptr), create_edge_dst_temp_expanded_(false), paste_command_(nullptr), - filter_mode_(kFilterShowSelective), scale_(1.0), - queue_reposition_contexts_(false) + first_show_(true) { setScene(&scene_); SetDefaultDragMode(RubberBandDrag); @@ -84,10 +82,10 @@ NodeView::~NodeView() ClearGraph(); } -void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes) +void NodeView::SetContexts(const QVector &nodes) { // Remove contexts that are no longer in the list - foreach (Node *n, filter_nodes_) { + foreach (Node *n, contexts_) { if (!nodes.contains(n)) { scene_.RemoveContext(n); } @@ -95,86 +93,38 @@ void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes) // Add contexts that are now in the list foreach (Node *n, nodes) { - if (!filter_nodes_.contains(n)) { + if (!contexts_.contains(n)) { scene_.AddContext(n); } } - filter_nodes_ = nodes; + contexts_ = nodes; - /*bool graph_changed = graph_ != graph; - bool context_changed = last_set_filter_nodes_ != nodes; + CenterOnItemsBoundingRect(); +} - if (graph_changed || context_changed) { - // Clear nodes if necessary - bool refresh_required = (graph_changed && filter_mode_ == kFilterShowAll) - || (context_changed && filter_mode_ == kFilterShowSelective); - bool nodes_visible = (graph && filter_mode_ == kFilterShowAll) - || (!nodes.isEmpty() && filter_mode_ == kFilterShowSelective); +void NodeView::CloseContextsBelongingToProject(Project *project) +{ + QVector new_contexts = contexts_; - if (refresh_required) { - DeselectAll(); - positions_.clear(); - scene_.clear(); - context_offsets_.clear(); + for (auto it = new_contexts.begin(); it != new_contexts.end(); ) { + if ((*it)->project() == project) { + it = new_contexts.erase(it); + } else { + it++; } + } - // Handle graph change - if (graph_changed) { - if (graph_) { - // Disconnect from current graph - disconnect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::RemoveNode); - disconnect(graph_, &NodeGraph::InputConnected, this, &NodeView::AddEdge); - disconnect(graph_, &NodeGraph::InputDisconnected, this, &NodeView::RemoveEdge); - disconnect(graph_, &NodeGraph::NodePositionAdded, this, &NodeView::AddNodePosition); - disconnect(graph_, &NodeGraph::NodePositionRemoved, this, &NodeView::RemoveNodePosition); - } - - graph_ = graph; - - if (graph_) { - // Connect to new graph - connect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::RemoveNode); - connect(graph_, &NodeGraph::InputConnected, this, &NodeView::AddEdge); - connect(graph_, &NodeGraph::InputDisconnected, this, &NodeView::RemoveEdge); - connect(graph_, &NodeGraph::NodePositionAdded, this, &NodeView::AddNodePosition); - connect(graph_, &NodeGraph::NodePositionRemoved, this, &NodeView::RemoveNodePosition); - } - } - - if (context_changed) { - last_set_filter_nodes_ = nodes; - - if (filter_mode_ == kFilterShowSelective) { - filter_nodes_ = nodes; - } - } - - if (refresh_required && nodes_visible) { - if (filter_mode_ == kFilterShowAll) { - // Just make the filter nodes all of the graph's contexts - filter_nodes_ = graph->GetPositionMap().keys().toVector(); - } - - RepositionContexts(); - - // Center on something - QMetaObject::invokeMethod(this, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection); - } - }*/ + SetContexts(new_contexts); } void NodeView::ClearGraph() { - SetGraph(nullptr, QVector()); + SetContexts(QVector()); } void NodeView::DeleteSelected() { - if (!graph_) { - return; - } - MultiUndoCommand* command = new MultiUndoCommand(); { @@ -189,9 +139,6 @@ void NodeView::DeleteSelected() command->add_child(new NodeEdgeRemoveCommand(edge->output(), edge->input())); removed_connections[i] = {edge->output(), edge->input()}; } - - // Update contexts - UpdateContextsFromEdgeRemove(command, removed_connections); } } @@ -219,10 +166,6 @@ void NodeView::DeleteSelected() void NodeView::SelectAll() { - if (!graph_) { - return; - } - // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. DisconnectSelectionChangedSignal(); @@ -249,7 +192,7 @@ void NodeView::SelectAll() void NodeView::DeselectAll() { - if (!graph_ || selected_nodes_.isEmpty()) { + if (selected_nodes_.isEmpty()) { return; } @@ -268,10 +211,6 @@ void NodeView::DeselectAll() void NodeView::Select(QVector nodes, bool center_view_on_item) { - if (!graph_) { - return; - } - // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. DisconnectSelectionChangedSignal(); @@ -331,39 +270,13 @@ void NodeView::Select(QVector nodes, bool center_view_on_item) selected_nodes_ = nodes; } -void NodeView::SelectWithDependencies(QVector nodes, bool center_view_on_item) -{ - if (!graph_) { - return; - } - - int original_length = nodes.size(); - for (int i=0;i dependencies = nodes.at(i)->GetDependencies(); - - foreach (Node *d, dependencies) { - if (scene_.item_map().contains(d) && !nodes.contains(d)) { - nodes.append(d); - } - } - } - - Select(nodes, center_view_on_item); -} - void NodeView::CopySelected(bool cut) { - if (!graph_) { + if (selected_nodes_.isEmpty()) { return; } - QVector selected = scene_.GetSelectedNodes(); - - if (selected.isEmpty()) { - return; - } - - CopyNodesToClipboard(selected); + CopyNodesToClipboard(selected_nodes_); if (cut) { DeleteSelected(); @@ -409,43 +322,41 @@ void NodeView::keyPressEvent(QKeyEvent *event) case Qt::Key_Up: case Qt::Key_Down: { - if (graph_) { - MultiUndoCommand *pos_command = new MultiUndoCommand(); - for (Node *n : qAsConst(selected_nodes_)) { - for (Node *context : qAsConst(filter_nodes_)) { - if (graph_->GetNodesForContext(context).contains(n)) { - QPointF old_pos = graph_->GetNodePosition(n, context); + MultiUndoCommand *pos_command = new MultiUndoCommand(); + for (Node *n : qAsConst(selected_nodes_)) { + for (Node *context : qAsConst(contexts_)) { + if (context->ContextContainsNode(n)) { + QPointF old_pos = context->GetNodePositionInContext(n); - // Determine one pixel in scene units - double movement_amt = 1.0 / scale_; + // Determine one pixel in scene units + double movement_amt = 1.0 / scale_; - // Translate to 2D movement - QPointF node_movement; - switch (event->key()) { - case Qt::Key_Left: - node_movement.setX(-movement_amt); - break; - case Qt::Key_Right: - node_movement.setX(movement_amt); - break; - case Qt::Key_Up: - node_movement.setY(-movement_amt); - break; - case Qt::Key_Down: - node_movement.setY(movement_amt); - break; - } - - // Translate from screen units into node units - node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection()); - - // Move command - pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement, false)); + // Translate to 2D movement + QPointF node_movement; + switch (event->key()) { + case Qt::Key_Left: + node_movement.setX(-movement_amt); + break; + case Qt::Key_Right: + node_movement.setX(movement_amt); + break; + case Qt::Key_Up: + node_movement.setY(-movement_amt); + break; + case Qt::Key_Down: + node_movement.setY(movement_amt); + break; } + + // Translate from screen units into node units + node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection()); + + // Move command + pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement)); } } - Core::instance()->undo_stack()->pushIfHasChildren(pos_command); } + Core::instance()->undo_stack()->pushIfHasChildren(pos_command); break; } case Qt::Key_Escape: @@ -664,15 +575,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event) create_edge_dst_ = nullptr; } - // Update contexts - /*if (!removed_edges.empty()) { - UpdateContextsFromEdgeRemove(command, removed_edges); - } - - if (added_edge.first) { - UpdateContextsFromEdgeAdd(command, added_edge, removed_edges); - }*/ - Core::instance()->undo_stack()->pushIfHasChildren(command); return; } @@ -689,38 +591,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event) } } - { - // If any node positions changed, set them in their contexts now - MultiUndoCommand *set_pos_command = new MultiUndoCommand(); - for (auto it=positions_.begin(); it!=positions_.end(); it++) { - NodeViewItem *item = it.key(); - Position &pos_data = it.value(); - QPointF current_item_pos = item->GetNodePosition(); - Node *node = pos_data.node; - - if (pos_data.original_item_pos != current_item_pos) { - QPointF diff = current_item_pos - pos_data.original_item_pos; - - for (Node *context : qAsConst(filter_nodes_)) { - if (graph_->ContextContainsNode(node, context)) { - QPointF current_node_pos_in_context = graph_->GetNodePosition(node, context); - current_node_pos_in_context += diff; - set_pos_command->add_child(new NodeSetPositionCommand(node, context, current_node_pos_in_context, false)); - } - } - - pos_data.original_item_pos = current_item_pos; - } - } - if (set_pos_command->child_count()) { - set_pos_command->redo_now(); - command->add_child(set_pos_command); - } else { - delete set_pos_command; - } - } - - if (!attached_items_.isEmpty()) { { // Dropped attached item onto an edge, connect it between them @@ -757,7 +627,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event) bool removed = false; QVector relevant_contexts; - for (Node *context : qAsConst(filter_nodes_)) { + for (Node *context : qAsConst(contexts_)) { if (attached_node->OutputsTo(context, true)) { relevant_contexts.append(context); } else { @@ -768,7 +638,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event) if (removed && !relevant_contexts.isEmpty()) { for (Node *relevant : qAsConst(relevant_contexts)) { - remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant), false)); + remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant))); } remove_pos_command->add_child(remove_pos_subcommand); @@ -844,7 +714,7 @@ void NodeView::UpdateSelectionCache() void NodeView::ShowContextMenu(const QPoint &pos) { - if (filter_nodes_.isEmpty()) { + if (contexts_.isEmpty()) { return; } @@ -896,17 +766,6 @@ void NodeView::ShowContextMenu(const QPoint &pos) m.addSeparator(); - Menu* filter_menu = new Menu(tr("Filter"), &m); - m.addMenu(filter_menu); - - filter_menu->AddActionWithData(tr("Show All Nodes"), kFilterShowAll, filter_mode_); - - filter_menu->AddActionWithData(tr("Show Selected"), kFilterShowSelective, filter_mode_); - - connect(filter_menu, &Menu::triggered, this, &NodeView::ContextMenuFilterChanged); - - - Menu* direction_menu = new Menu(tr("Direction"), &m); m.addMenu(direction_menu); @@ -940,23 +799,20 @@ void NodeView::ShowContextMenu(const QPoint &pos) void NodeView::CreateNodeSlot(QAction *action) { - if (!graph_) { - return; - } - - Node* new_node = NodeFactory::CreateFromMenuAction(action); + qDebug() << "STUB!"; + /*Node* new_node = NodeFactory::CreateFromMenuAction(action); if (new_node) { paste_command_ = new MultiUndoCommand(); paste_command_->add_child(new NodeAddCommand(graph_, new_node)); - for (Node *context : qAsConst(filter_nodes_)) { + for (Node *context : qAsConst(contexts_)) { paste_command_->add_child(new NodeSetPositionCommand(new_node, context, QPointF(0, 0), false)); } paste_command_->add_child(new NodeViewAttachNodesToCursor(this, {new_node})); paste_command_->redo_now(); this->setFocus(); - } + }*/ } void NodeView::ContextMenuSetDirection(QAction *action) @@ -964,26 +820,6 @@ void NodeView::ContextMenuSetDirection(QAction *action) SetFlowDirection(static_cast(action->data().toInt())); } -void NodeView::ContextMenuFilterChanged(QAction *action) -{ - FilterMode mode = static_cast(action->data().toInt()); - - if (filter_mode_ != mode) { - // Store temporary graph variables - NodeGraph *graph = graph_; - QVector nodes = last_set_filter_nodes_; - - // Unset graph with current filter mode - ClearGraph(); - - // Change filter mode - filter_mode_ = mode; - - // Re-set graph with new filter mode - SetGraph(graph, nodes); - } -} - void NodeView::OpenSelectedNodeInViewer() { QVector selected = scene_.GetSelectedNodes(); @@ -994,100 +830,6 @@ void NodeView::OpenSelectedNodeInViewer() } } -// Commenting out because there shouldn't be any situations where a node would be added without -// being in a context. We're keeping RemoveNode as a fail-safe because it could provide crash -// resistance where RemoveNodePosition might be missed. -//void NodeView::AddNode(Node *node) -//{ -// if (filter_mode_ == kFilterShowAll) { -// scene_.AddNode(node); -// } -//} - -void NodeView::RemoveNode(Node *node) -{ - for (auto it=attached_items_.begin(); it!=attached_items_.end(); ) { - if (it->item->GetNode() == node) { - it = attached_items_.erase(it); - } else { - it++; - } - } - for (const Node::OutputConnection &oc : node->output_connections()) { - scene_.RemoveEdge(oc.first, oc.second); - } - for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { - scene_.RemoveEdge(it->second, it->first); - } - positions_.remove(scene_.item_map().value(node)); -} - -void NodeView::AddEdge(Node *output, const NodeInput &input) -{ - Node *output_node = output; - Node *input_node = input.node(); - - if (scene_.item_map().contains(output_node) && scene_.item_map().contains(input_node)) { - scene_.AddEdge(output, input); - } -} - -void NodeView::RemoveEdge(Node *output, const NodeInput &input) -{ - scene_.RemoveEdge(output, input); -} - -void NodeView::AddNodePosition(Node *node, Node *relative) -{ - bool listening_to_node = filter_nodes_.contains(relative); - - if (!listening_to_node) { - if (filter_mode_ == kFilterShowAll) { - // We're not listening to this context, but because we're showing all, add it - filter_nodes_.append(relative); - } else { - // Ignore signal - return; - } - } - - // Reposition contexts because one of their heights may have changed or a new one may have been - // added - UpdateNodeItem(node); - - if (filter_mode_ == kFilterShowAll) { - queue_reposition_contexts_ = true; - viewport()->update(); - } -} - -void NodeView::RemoveNodePosition(Node *node, Node *relative) -{ - if (filter_nodes_.contains(relative)) { - NodeViewItem *item = scene_.item_map().value(node); - - if (item && !item->GetPreventRemoving()) { - // Determine if any other contexts have this node - bool found = false; - - for (Node *context : qAsConst(filter_nodes_)) { - if (graph_->ContextContainsNode(node, context)) { - found = true; - break; - } - } - - if (!found) { - RemoveNode(node); - } - } - - if (filter_mode_ == kFilterShowAll) { - RepositionContexts(); - } - } -} - void NodeView::UpdateSceneBoundingRect() { // Get current items bounding rect @@ -1229,13 +971,6 @@ bool NodeView::event(QEvent *event) bool NodeView::eventFilter(QObject *object, QEvent *event) { - if (object == viewport() && event->type() == QEvent::Paint) { - if (queue_reposition_contexts_) { - RepositionContexts(); - queue_reposition_contexts_ = false; - } - } - return super::eventFilter(object, event); } @@ -1259,7 +994,8 @@ void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVec void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata) { - NodeGraph::PositionMap *map = static_cast(userdata); + qDebug() << "STUB!"; + /*NodeGraph::PositionMap *map = static_cast(userdata); while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("pos")) { @@ -1295,7 +1031,7 @@ void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNode } else { reader->skipCurrentElement(); } - } + }*/ } void NodeView::ZoomFromKeyboard(double multiplier) @@ -1310,148 +1046,6 @@ void NodeView::ZoomFromKeyboard(double multiplier) ZoomIntoCursorPosition(nullptr, multiplier, cursor_pos); } -bool NodeView::DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge) -{ - // Determines whether `node` outputs to another node in `context` besides `source` - for (const Node::OutputConnection &conn : node->output_connections()) { - Node *output_candidate = conn.second.node(); - - if (output_candidate == source) { - continue; - } - - if (graph_->ContextContainsNode(output_candidate, context)) { - if (!output_candidate->OutputsTo(source, true, removed_edges, added_edge)) { - return true; - } - } - } - - return false; -} - -void NodeView::UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges) -{ - // For each edge we remove, determine if we should remove the node from a context as well - for (const Node::OutputConnection &edge : remove_edges) { - Node *output_node = edge.first; - QVector contexts_to_remove_from; - int contexts_containing = 0; - - for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) { - Node *context = it.key(); - - if (it.value().contains(output_node)) { - bool currently_outputs = output_node->OutputsTo(context, true); - bool will_output_after_operation = output_node->OutputsTo(context, true, remove_edges); - - if (currently_outputs && !will_output_after_operation) { - // Will remove - contexts_to_remove_from.append(context); - } - - contexts_containing++; - } - } - - // Removing from all current contexts, convert to a floating node (i.e. don't remove from the context) - if (contexts_to_remove_from.size() != contexts_containing) { - // Not removing from all contexts, can remove - bool removing_from_all_current_contexts = true; - - for (Node *context : qAsConst(filter_nodes_)) { - if (graph_->ContextContainsNode(output_node, context)) { - if (!contexts_to_remove_from.contains(context)) { - removing_from_all_current_contexts = false; - break; - } - } - } - - for (Node *context : qAsConst(contexts_to_remove_from)) { - RecursivelyRemoveFloatingNodeFromContext(command, output_node, context, output_node, remove_edges, Node::OutputConnection(), removing_from_all_current_contexts); - } - } - } -} - -void NodeView::RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing) -{ - if (prevent_removing) { - command->add_child(new NodeViewItemPreventRemovingCommand(this, node, true)); - } - - command->add_child(new NodeRemovePositionFromContextCommand(node, context)); - - // Remove any dependency from the context that's also floating - for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { - Node *dependency = it->second; - - // Determine if this node happens to output to anything else in the context (which may be - // another floating node that won't be removed by this operation) - if (!DetermineIfNodeIsFloatingInContext(dependency, context, source, removed_edges, added_edge)) { - RecursivelyRemoveFloatingNodeFromContext(command, dependency, context, source, removed_edges, added_edge, prevent_removing); - } - } -} - -void NodeView::RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context) -{ - NodeViewItem *item = scene_.item_map().value(node); - - if (item) { - command->add_child(new NodeSetPositionCommand(node, context, GetEstimatedPositionForContext(item, context), false)); - - // Add dependency - for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { - Node *dependency = it->second; - RecursivelyAddNodeToContext(command, dependency, context); - } - } -} - -void NodeView::UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges) -{ - // Determine if node currently does NOT output to a context that it WILL after this operation - QVector contexts_to_add_to; - Node *connecting_node = added_edge.first; - Node *input_node = added_edge.second.node(); - for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) { - if (it.value().contains(input_node)) { - contexts_to_add_to.append(it.key()); - } - } - - if (!contexts_to_add_to.isEmpty()) { - // Determine whether the node is currently "floating", i.e. it outputs to none of the contexts - // that it currently belongs to. If so, we will take ownership of it with this node. - bool node_is_floating = true; - QVector current_contexts; - for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) { - if (it.value().contains(connecting_node)) { - if (connecting_node->OutputsTo(it.key(), true, removed_edges)) { - node_is_floating = false; - break; - } else { - current_contexts.append(it.key()); - } - } - } - - if (node_is_floating) { - // This action will unfloat this node, so remove it from all current contexts - for (Node *context : qAsConst(current_contexts)) { - RecursivelyRemoveFloatingNodeFromContext(command, connecting_node, context, connecting_node, removed_edges, added_edge, false); - } - } - - // Add nodes to contexts - for (Node *context : qAsConst(contexts_to_add_to)) { - RecursivelyAddNodeToContext(command, connecting_node, context); - } - } -} - QPointF NodeView::GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const { return item->GetNodePosition() - context_offsets_.value(context); @@ -1545,86 +1139,6 @@ void NodeView::PositionNewEdge(const QPoint &pos) create_edge_->SetConnected(create_edge_dst_input_.IsValid()); } -void NodeView::RepositionContexts() -{ - // Determine which contexts are root-level - QVector processing_filters = filter_nodes_; - - // Level counter as we iterate through the list a few times - int level = 0; - - // Root-level positioning variables - qreal last_offset = 0; - int additional_spacing = 0; - - while (!processing_filters.isEmpty()) { - QVector contexts_on_this_level; - - for (int i=0; iContextContainsNode(context, other_context)) { - this_level = false; - break; - } - } - - if (this_level) { - contexts_on_this_level.append(context); - } - } - - for (Node *context : qAsConst(contexts_on_this_level)) { - if (level == 0) { - const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context); - - // First determine the total "height" of this graph and how much we need to offset it - qreal top = 0; - qreal bottom = 0; - for (auto it=map.cbegin(); it!=map.cend(); it++) { - const QPointF &node_pos_in_context = it.value(); - top = qMin(node_pos_in_context.y(), top); - bottom = qMax(node_pos_in_context.y(), bottom); - } - - last_offset += (additional_spacing + (bottom - top)); - additional_spacing = 1; - context_offsets_.insert(context, QPointF(0, last_offset)); - } else { - // Create/update item - NodeViewItem *item = UpdateNodeItem(context, true); - - // Get position generated by UpdateNodeItem - QPointF context_pos = item->GetNodePosition(); - - // Adjust by the context node's position in its own context (this will usually be 0,0) - context_pos -= graph_->GetNodesForContext(context).value(context); - - // Insert this context's offset - context_offsets_.insert(context, context_pos); - } - - // Remove from list so we don't process again - processing_filters.removeOne(context); - } - - level++; - } - - // Now that we've positioned all the contexts, position all other nodes relative to those contexts - for (Node *context : qAsConst(filter_nodes_)) { - const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context); - for (auto it=map.cbegin(); it!=map.cend(); it++) { - UpdateNodeItem(it.key()); - } - } -} - void NodeView::GroupNodes() { /*NodeGroup *group = new NodeGroup(); @@ -1636,54 +1150,11 @@ void NodeView::UngroupNodes() //static_cast(selected_nodes_.first()); } -NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context) -{ - // Get UI item or create if it doesn't exist - NodeViewItem *item = scene_.item_map().value(node); - if (!item) { - for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { - if (scene_.item_map().contains(it->second)) { - scene_.AddEdge(it->second, it->first); - } - } - - for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) { - if (scene_.item_map().contains(it->second.node())) { - scene_.AddEdge(it->first, it->second); - } - } - } - - // Determine "view" position by averaging the Y value and "min"ing the X value of all contexts - QPointF item_pos(std::numeric_limits::max(), 0.0); - int average_count = 0; - for (Node *context : qAsConst(filter_nodes_)) { - if (context == node && ignore_own_context) { - continue; - } - - if (graph_->GetNodesForContext(context).contains(node)) { - QPointF this_context_pos = graph_->GetNodePosition(node, context); - this_context_pos += context_offsets_.value(context); - - item_pos.setX(qMin(item_pos.x(), this_context_pos.x())); - item_pos.setY(item_pos.y() + this_context_pos.y()); - average_count++; - } - } - item_pos.setY(item_pos.y() / average_count); - - // Set position - item->SetNodePosition(item_pos); - positions_.insert(item, {node, item_pos}); - - return item; -} - void NodeView::PasteNodesInternal(const QVector &duplicate_nodes) { + /* // If no graph, do nothing - if (!graph_) { + if (contexts_.isEmpty()) { return; } @@ -1696,7 +1167,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes) new_nodes = PasteNodesFromClipboard(graph_, paste_command_, &map); for (auto it=new_nodes.cbegin(); it!=new_nodes.cend(); it++) { - for (Node *context : qAsConst(filter_nodes_)) { + for (Node *context : qAsConst(contexts_)) { paste_command_->add_child(new NodeSetPositionCommand(*it, context, map.value(*it), false)); } } @@ -1707,7 +1178,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes) Node *src = duplicate_nodes.at(i); Node *copy = new_nodes.at(i); - for (Node *context : qAsConst(filter_nodes_)) { + for (Node *context : qAsConst(contexts_)) { QPointF p = scene_.item_map().value(src)->GetNodePosition(); paste_command_->add_child(new NodeSetPositionCommand(copy, context, p, false)); } @@ -1725,6 +1196,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes) paste_command_->add_child(new NodeViewAttachNodesToCursor(this, new_nodes)); paste_command_->redo_now(); + */ } NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector &nodes) : @@ -1745,8 +1217,7 @@ void NodeView::NodeViewAttachNodesToCursor::undo() Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const { - // Will either return a project or a nullptr which is also acceptable - return dynamic_cast(view_->graph_); + return nullptr; } void NodeView::NodeViewItemPreventRemovingCommand::redo() diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 941120361..8616974f5 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -49,12 +49,9 @@ public: virtual ~NodeView() override; - NodeGraph* GetGraph() const - { - return graph_; - } + void SetContexts(const QVector &nodes); - void SetGraph(NodeGraph *graph, const QVector &nodes); + void CloseContextsBelongingToProject(Project *project); void ClearGraph(); @@ -67,7 +64,6 @@ public: void DeselectAll(); void Select(QVector nodes, bool center_view_on_item); - void SelectWithDependencies(QVector nodes, bool center_view_on_item); void CopySelected(bool cut); void Paste(); @@ -82,7 +78,7 @@ public: const QVector &GetCurrentContexts() const { - return filter_nodes_; + return contexts_; } public slots: @@ -98,6 +94,8 @@ public slots: delete m; } + void CenterOnItemsBoundingRect(); + signals: void NodesSelected(const QVector& nodes); @@ -137,12 +135,6 @@ private: void ZoomFromKeyboard(double multiplier); - bool DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge); - void UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges); - void UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges = Node::OutputConnections()); - void RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context); - void RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing); - QPointF GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const; Menu *CreateAddMenu(Menu *parent); @@ -151,8 +143,6 @@ private: void PositionNewEdge(const QPoint &pos); - NodeViewItem *UpdateNodeItem(Node *node, bool ignore_own_context = false); - void PasteNodesInternal(const QVector &duplicate_nodes = QVector()); class NodeViewAttachNodesToCursor : public UndoCommand @@ -176,8 +166,6 @@ private: NodeViewMiniMap *minimap_; - NodeGraph* graph_; - struct AttachedItem { NodeViewItem* item; QPointF original_pos; @@ -227,21 +215,7 @@ private: QVector selected_nodes_; - enum FilterMode { - kFilterShowAll, - kFilterShowSelective - }; - - struct Position { - Node *node; - QPointF original_item_pos; - }; - - QMap positions_; - - FilterMode filter_mode_; - - QVector filter_nodes_; + QVector contexts_; QVector last_set_filter_nodes_; QMap context_offsets_; @@ -249,7 +223,7 @@ private: bool create_edge_already_exists_; - bool queue_reposition_contexts_; + bool first_show_; static const double kMinimumScale; @@ -274,36 +248,19 @@ private slots: */ void ContextMenuSetDirection(QAction* action); - /** - * @brief Receiver for the user changing the filter - */ - void ContextMenuFilterChanged(QAction* action); - /** * @brief Opens the selected node in a Viewer */ void OpenSelectedNodeInViewer(); - //void AddNode(Node *node); - void RemoveNode(Node *node); - void AddEdge(Node *output, const NodeInput& input); - void RemoveEdge(Node *output, const NodeInput& input); - - void AddNodePosition(Node *node, Node *relative); - void RemoveNodePosition(Node *node, Node *relative); - void UpdateSceneBoundingRect(); - void CenterOnItemsBoundingRect(); - void RepositionMiniMap(); void UpdateViewportOnMiniMap(); void MoveToScenePoint(const QPointF &pos); - void RepositionContexts(); - void GroupNodes(); void UngroupNodes(); diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp index db22be143..1b52624a6 100644 --- a/app/widget/nodeview/nodeviewcontext.cpp +++ b/app/widget/nodeview/nodeviewcontext.cpp @@ -19,37 +19,29 @@ namespace olive { #define super QGraphicsRectItem -NodeViewContext::NodeViewContext(QGraphicsItem *item) : - super(item) +NodeViewContext::NodeViewContext(Node *context, QGraphicsItem *item) : + super(item), + context_(context) { - // Set default label text - SetContext(nullptr); -} - -void NodeViewContext::SetContext(Node *node) -{ - context_ = node; - - if (context_) { - if (Block *block = dynamic_cast(node)) { - rational timebase = block->track()->sequence()->GetVideoParams().frame_rate_as_time_base(); - lbl_ = QCoreApplication::translate("NodeViewContext", - "%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(), - Track::Reference::TypeToTranslatedString(block->track()->type()), - Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()), - Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay())); - } else { - lbl_ = node->GetLabelAndName(); - } - - Color c = node->color(); - setPen(QPen(c.toQColor(), 2)); - - c.set_alpha(0.5f); - setBrush(c.toQColor()); + if (Block *block = dynamic_cast(context_)) { + rational timebase = block->track()->sequence()->GetVideoParams().frame_rate_as_time_base(); + lbl_ = QCoreApplication::translate("NodeViewContext", + "%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(), + Track::Reference::TypeToTranslatedString(block->track()->type()), + Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()), + Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay())); } else { - lbl_ = QCoreApplication::translate("NodeViewContext", "(None)"); + lbl_ = context_->GetLabelAndName(); } + + const Node::PositionMap &map = context_->GetContextPositions(); + for (auto it=map.cbegin(); it!=map.cend(); it++) { + AddChild(it.key()); + } + + connect(context_, &Node::NodeAddedToContext, this, &NodeViewContext::AddChild, Qt::DirectConnection); + connect(context_, &Node::NodePositionInContextChanged, this, &NodeViewContext::SetChildPosition, Qt::DirectConnection); + connect(context_, &Node::NodeRemovedFromContext, this, &NodeViewContext::RemoveChild, Qt::DirectConnection); } void NodeViewContext::AddChild(Node *node) @@ -59,33 +51,73 @@ void NodeViewContext::AddChild(Node *node) } NodeViewItem *item = new NodeViewItem(this); - item->SetNode(node); - item->SetNodePosition(context_->parent()->GetNodesForContext(context_).value(node)); + item->SetNode(node, context_); + item->SetNodePosition(context_->GetNodePositionInContext(node)); item->SetFlowDirection(flow_dir_); + connect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected); + connect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected); + + item_map_.insert(node, item); + if (node == context_) { item->SetLabelAsOutput(true); } for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) { - foreach (auto child, childItems()) { - if (NodeViewItem *other_item = dynamic_cast(child)) { - if (other_item->GetNode() == it->second.node()) { - AddEdgeInternal(node, it->second, item, other_item); - } + if (!it->second.IsHidden()) { + if (NodeViewItem *other_item = item_map_.value(it->second.node())) { + AddEdgeInternal(node, it->second, item, other_item); } } } for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { - foreach (auto child, childItems()) { - if (NodeViewItem *other_item = dynamic_cast(child)) { - if (it->second == other_item->GetNode()) { - AddEdgeInternal(it->second, it->first, other_item, item); - } + if (!it->first.IsHidden()) { + if (NodeViewItem *other_item = item_map_.value(it->second)) { + AddEdgeInternal(it->second, it->first, other_item, item); } } } + + UpdateRect(); +} + +void NodeViewContext::SetChildPosition(Node *node, const QPointF &pos) +{ + item_map_.value(node)->SetNodePosition(pos); +} + +void NodeViewContext::RemoveChild(Node *node) +{ + disconnect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected); + disconnect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected); + + delete item_map_.take(node); +} + +void NodeViewContext::ChildInputConnected(Node *output, const NodeInput &input) +{ + // Add edge + if (!input.IsHidden()) { + if (NodeViewItem* output_item = item_map_.value(output)) { + AddEdgeInternal(output, input, output_item, item_map_.value(input.node())); + } + } +} + +bool NodeViewContext::ChildInputDisconnected(Node *output, const NodeInput &input) +{ + // Remove edge + for (int i=0; ioutput() == output && edges_.at(i)->input() == input) { + delete edges_.at(i); + edges_.removeAt(i); + return true; + } + } + + return false; } qreal GetTextOffset(const QFontMetricsF &fm) @@ -105,23 +137,19 @@ void NodeViewContext::UpdateRect() rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad); setRect(rect); - last_titlebar_height_ = rect.y() + (cbr.y() - rect.y()); + last_titlebar_height_ = rect.y() + (cbr.y() - rect.y()) - pad; } void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir) { flow_dir_ = dir; - foreach (auto child, childItems()) { - if (NodeViewItem *item = dynamic_cast(child)) { - item->SetFlowDirection(dir); - } + foreach (NodeViewItem *item, item_map_) { + item->SetFlowDirection(dir); } - foreach (auto child, childItems()) { - if (NodeViewEdge *edge = dynamic_cast(child)) { - edge->SetFlowDirection(dir); - } + foreach (NodeViewEdge *edge, edges_) { + edge->SetFlowDirection(dir); } } @@ -129,29 +157,40 @@ void NodeViewContext::SetCurvedEdges(bool e) { curved_edges_ = e; - const QList &children = childItems(); - foreach (auto child, children) { - if (NodeViewEdge *edge = dynamic_cast(child)) { - edge->SetCurved(e); - } + foreach (NodeViewEdge *edge, edges_) { + edge->SetCurved(e); } } void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - QPen p = pen(); - + // Set pen and brush + Color color = context_->color(); + QColor c = color.toQColor(); + QPen pen(c, 2); if (option->state & QStyle::State_Selected) { - p.setStyle(Qt::DotLine); + pen.setStyle(Qt::DotLine); } + painter->setPen(pen); - painter->setPen(p); - painter->setBrush(brush()); + QColor bg = c; + bg.setAlpha(128); + painter->setBrush(bg); + // Draw semi-transparent rect for whole item int rounded = painter->fontMetrics().height(); painter->drawRoundedRect(rect(), rounded, rounded); - painter->setPen(widget->palette().text().color()); + // Draw solid background for titlebar + QRectF titlebar_rect = rect(); + titlebar_rect.setHeight(last_titlebar_height_ - rect().top()); + painter->setClipRect(titlebar_rect); + painter->setBrush(c); + painter->drawRoundedRect(rect(), rounded, rounded); + painter->setClipping(false); + + // Draw titlebar text + painter->setPen(ColorCoding::GetUISelectorColor(color)); int offset = GetTextOffset(painter->fontMetrics()); @@ -182,8 +221,7 @@ NodeViewEdge* NodeViewContext::AddEdgeInternal(Node *output, const NodeInput& in edge_ui->SetFlowDirection(flow_dir_); edge_ui->SetCurved(curved_edges_); - from->AddEdge(edge_ui); - to->AddEdge(edge_ui); + edges_.append(edge_ui); return edge_ui; } diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h index cf35b6fd2..4ef21f68f 100644 --- a/app/widget/nodeview/nodeviewcontext.h +++ b/app/widget/nodeview/nodeviewcontext.h @@ -10,14 +10,11 @@ namespace olive { -class NodeViewContext : public QGraphicsRectItem +class NodeViewContext : public QObject, public QGraphicsRectItem { + Q_OBJECT public: - NodeViewContext(QGraphicsItem *item = nullptr); - - void SetContext(Node *node); - - void AddChild(Node *node); + NodeViewContext(Node *context, QGraphicsItem *item = nullptr); void UpdateRect(); @@ -27,6 +24,17 @@ public: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; +public slots: + void AddChild(Node *node); + + void SetChildPosition(Node *node, const QPointF &pos); + + void RemoveChild(Node *node); + + void ChildInputConnected(Node *output, const NodeInput& input); + + bool ChildInputDisconnected(Node *output, const NodeInput& input); + protected: virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; @@ -45,6 +53,10 @@ private: int last_titlebar_height_; + QMap item_map_; + + QVector edges_; + }; } diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index 977b88cbd..caf629007 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -46,6 +46,9 @@ NodeViewEdge::NodeViewEdge(Node *output, const NodeInput &input, { Init(); SetConnected(true); + + from_item_->AddEdge(this); + to_item_->AddEdge(this); } NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : @@ -56,6 +59,17 @@ NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : Init(); } +NodeViewEdge::~NodeViewEdge() +{ + if (from_item_) { + from_item_->RemoveEdge(this); + } + + if (to_item_) { + to_item_->RemoveEdge(this); + } +} + void NodeViewEdge::Adjust() { // Draw a line between the two diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h index de8d10720..31a56664e 100644 --- a/app/widget/nodeview/nodeviewedge.h +++ b/app/widget/nodeview/nodeviewedge.h @@ -45,6 +45,8 @@ public: NodeViewEdge(QGraphicsItem* parent = nullptr); + virtual ~NodeViewEdge() override; + Node *output() const { return output_; diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index b3e4ee4e9..1c73f8ddd 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -42,6 +42,7 @@ namespace olive { NodeViewItem::NodeViewItem(QGraphicsItem *parent) : QGraphicsRectItem(parent), node_(nullptr), + context_(nullptr), expanded_(false), hide_titlebar_(false), highlighted_index_(-1), @@ -207,7 +208,7 @@ int NodeViewItem::GetIndexAt(QPointF pt) const return -1; } -void NodeViewItem::SetNode(Node *n) +void NodeViewItem::SetNode(Node *n, Node *context) { if (node_) { disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged); @@ -215,6 +216,7 @@ void NodeViewItem::SetNode(Node *n) } node_ = n; + context_ = context; node_inputs_.clear(); input_connectors_.clear(); @@ -223,7 +225,7 @@ void NodeViewItem::SetNode(Node *n) node_->Retranslate(); foreach (const QString& input, node_->inputs()) { - if (node_->IsInputConnectable(input)) { + if (node_->IsInputConnectable(input) && !node_->IsInputHidden(input)) { node_inputs_.append(input); } } @@ -327,9 +329,11 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti int icon_size = painter->fontMetrics().height()/2; + bool draw_arrow = !node_inputs_.isEmpty(); + if (node_label.isEmpty()) { // Draw shortname only - DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, true); + DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, draw_arrow); } else { int text_pad = DefaultTextPadding()/2; QRectF safe_label_bounds = title_bar_rect_.adjusted(text_pad, text_pad, -text_pad, -text_pad); @@ -337,7 +341,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti qreal font_sz = f.pointSizeF(); f.setPointSizeF(font_sz * 0.8); painter->setFont(f); - DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, true); + DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, draw_arrow); f.setPointSizeF(font_sz * 0.6); painter->setFont(f); DrawNodeTitle(painter, node_shortname, safe_label_bounds, Qt::AlignBottom, icon_size, false); diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 0f11574ed..b92f531c7 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -53,7 +53,7 @@ public: /** * @brief Set the Node to correspond to this widget */ - void SetNode(Node* n); + void SetNode(Node* n, Node *context); /** * @brief Get currently attached node @@ -174,6 +174,8 @@ private: */ Node* node_; + Node *context_; + /** * @brief Cached list of node inputs */ diff --git a/app/widget/nodeview/nodeviewminimap.cpp b/app/widget/nodeview/nodeviewminimap.cpp index d1e20791c..8dc99c914 100644 --- a/app/widget/nodeview/nodeviewminimap.cpp +++ b/app/widget/nodeview/nodeviewminimap.cpp @@ -38,6 +38,7 @@ NodeViewMiniMap::NodeViewMiniMap(NodeViewScene *scene, QWidget *parent) : setViewportUpdateMode(FullViewportUpdate); setFrameShape(QFrame::Panel); setFrameShadow(QFrame::Plain); + setMouseTracking(true); QMetaObject::invokeMethod(this, &NodeViewMiniMap::SetDefaultSize, Qt::QueuedConnection); @@ -87,7 +88,7 @@ void NodeViewMiniMap::resizeEvent(QResizeEvent *event) void NodeViewMiniMap::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - if (event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_) { + if (MouseInsideResizeTriangle(event)) { // Resizing! resizing_ = true; resize_anchor_ = QCursor::pos(); @@ -107,6 +108,8 @@ void NodeViewMiniMap::mouseMoveEvent(QMouseEvent *event) } else { EmitMoveSignal(event); } + } else { + setCursor(MouseInsideResizeTriangle(event) ? Qt::SizeFDiagCursor : Qt::ArrowCursor); } } @@ -135,6 +138,11 @@ void NodeViewMiniMap::SetDefaultSize() } } +bool NodeViewMiniMap::MouseInsideResizeTriangle(QMouseEvent *event) +{ + return event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_; +} + void NodeViewMiniMap::EmitMoveSignal(QMouseEvent *event) { emit MoveToScenePoint(mapToScene(event->pos())); diff --git a/app/widget/nodeview/nodeviewminimap.h b/app/widget/nodeview/nodeviewminimap.h index a63db1993..e155b54f2 100644 --- a/app/widget/nodeview/nodeviewminimap.h +++ b/app/widget/nodeview/nodeviewminimap.h @@ -57,6 +57,8 @@ private slots: void SetDefaultSize(); private: + bool MouseInsideResizeTriangle(QMouseEvent *event); + void EmitMoveSignal(QMouseEvent *event); int resize_triangle_sz_; diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index feb2598b3..2e04a2ae6 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -143,45 +143,25 @@ QVector NodeViewScene::GetSelectedEdges() const return edges; } -NodeViewEdge* NodeViewScene::AddEdge(Node *output, const NodeInput &input) -{ - NodeViewEdge *edge = EdgeToUIObject(output, input); - - if (!edge) { - edge = AddEdgeInternal(output, input, NodeToUIObject(output), NodeToUIObject(input.node())); - } - - return edge; -} - -void NodeViewScene::RemoveEdge(Node *output, const NodeInput &input) -{ - NodeViewEdge* edge = EdgeToUIObject(output, input); - if (edge) { - edge->from_item()->RemoveEdge(edge); - edge->to_item()->RemoveEdge(edge); - edges_.removeOne(edge); - delete edge; - } -} - NodeViewContext *NodeViewScene::AddContext(Node *node) { NodeViewContext *context_item = context_map_.value(node); if (!context_item) { - context_item = new NodeViewContext(); - context_item->SetContext(node); - context_item->setPos(0, 0); + context_item = new NodeViewContext(node); + context_item->SetFlowDirection(GetFlowDirection()); context_item->SetCurvedEdges(GetEdgesAreCurved()); - addItem(context_item); - const NodeGraph::PositionMap &map = node->parent()->GetNodesForContext(node); - for (auto it=map.cbegin(); it!=map.cend(); it++) { - context_item->AddChild(it.key()); + QPointF pos(0, 0); + QRectF item_rect = context_item->rect(); + while (!items(item_rect).isEmpty()) { + pos.setY(pos.y() + item_rect.height()); + item_rect = context_item->rect().translated(pos); } - context_item->UpdateRect(); + context_item->setPos(pos); + + addItem(context_item); context_map_.insert(node, context_item); } @@ -209,22 +189,6 @@ int NodeViewScene::DetermineWeight(Node *n) return qMax(1, weight); } -NodeViewEdge* NodeViewScene::AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to) -{ - NodeViewEdge* edge_ui = new NodeViewEdge(output, input, from, to); - - edge_ui->SetFlowDirection(direction_); - edge_ui->SetCurved(curved_edges_); - - from->AddEdge(edge_ui); - to->AddEdge(edge_ui); - - addItem(edge_ui); - edges_.append(edge_ui); - - return edge_ui; -} - Qt::Orientation NodeViewScene::GetFlowOrientation() const { return NodeViewCommon::GetFlowOrientation(direction_); @@ -240,8 +204,8 @@ void NodeViewScene::SetEdgesAreCurved(bool curved) if (curved_edges_ != curved) { curved_edges_ = curved; - foreach (NodeViewEdge* e, edges_) { - e->SetCurved(curved_edges_); + foreach (NodeViewContext *ctx, context_map_) { + ctx->SetCurvedEdges(curved_edges_); } } } diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index f37ebbdcd..db49aca89 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -81,9 +81,6 @@ public: } public slots: - NodeViewEdge *AddEdge(Node *output, const NodeInput& input); - void RemoveEdge(Node *output, const NodeInput& input); - NodeViewContext *AddContext(Node *node); void RemoveContext(Node *node); @@ -95,8 +92,6 @@ public slots: private: static int DetermineWeight(Node* n); - NodeViewEdge* AddEdgeInternal(Node *output, const NodeInput &input, NodeViewItem* from, NodeViewItem* to); - QHash context_map_; QHash item_map_; diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index 07343ccd3..a9c9d3615 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -116,7 +116,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) NodeGraph* graph = static_cast(parent()->GetConnectedNode()->parent()); command->add_child(new NodeAddCommand(graph, clip)); - command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false)); + command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0))); command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()), track.index(), clip, @@ -155,10 +155,10 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) } if (node_to_add) { - QPointF extra_node_offset(-1, 0); + QPointF extra_node_offset(kDefaultDistanceFromOutput, 0); command->add_child(new NodeAddCommand(graph, node_to_add)); command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset, false)); + command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset)); } Core::instance()->undo_stack()->push(command); diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 9ad1a6a74..f9ab4b6f8 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -355,7 +355,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeAddCommand(dst_graph, new_sequence)); command->add_child(new FolderAddChild(Core::instance()->GetSelectedFolderInActiveProject(), new_sequence)); - command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false)); + command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0))); new_sequence->add_default_nodes(command); FootageToGhosts(0, dragged_footage_, new_sequence->GetVideoParams().time_base(), 0); @@ -394,10 +394,14 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeAddCommand(dst_graph, clip)); // Position clip in its own context - command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false)); + command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0))); + + int dep_pos = kDefaultDistanceFromOutput; // Position footage in its context - command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(-3, 0), false)); + command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(dep_pos, 0))); + + dep_pos++; switch (Track::Reference::TypeFromString(footage_stream.output)) { case Track::kVideo: @@ -409,7 +413,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(transform, TransformDistortNode::kTextureInput))); command->add_child(new NodeEdgeAddCommand(transform, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(-2, 0), false)); + command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(dep_pos, 0))); break; } case Track::kAudio: @@ -421,7 +425,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(volume_node, VolumeNode::kSamplesInput))); command->add_child(new NodeEdgeAddCommand(volume_node, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(-2, 0), false)); + command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(dep_pos, 0))); break; } default: diff --git a/app/widget/timelinewidget/tool/tool.cpp b/app/widget/timelinewidget/tool/tool.cpp index 752409b78..2612b9697 100644 --- a/app/widget/timelinewidget/tool/tool.cpp +++ b/app/widget/timelinewidget/tool/tool.cpp @@ -24,6 +24,8 @@ namespace olive { +const int TimelineTool::kDefaultDistanceFromOutput = -4; + TimelineTool::TimelineTool(TimelineWidget *parent) : dragging_(false), parent_(parent) diff --git a/app/widget/timelinewidget/tool/tool.h b/app/widget/timelinewidget/tool/tool.h index d229e1ad3..c627f542e 100644 --- a/app/widget/timelinewidget/tool/tool.h +++ b/app/widget/timelinewidget/tool/tool.h @@ -84,6 +84,8 @@ protected: TimelineCoordinate drag_start_; + static const int kDefaultDistanceFromOutput; + private: TimelineWidget* parent_; diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index f1a1f4fdd..594659ccb 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -113,7 +113,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), transition)); - command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0), false)); + command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0))); command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()), track.index(), @@ -138,8 +138,8 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(new NodeEdgeAddCommand(in_block, NodeInput(transition, TransitionBlock::kInBlockInput))); - command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5), false)); - command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5), false)); + command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5))); + command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5))); } else { Block* block_to_transition = Node::ValueToPtr(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock)); QString transition_input_to_connect; @@ -154,7 +154,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(new NodeEdgeAddCommand(block_to_transition, NodeInput(transition, transition_input_to_connect))); - command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0), false)); + command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0))); } Core::instance()->undo_stack()->push(command); diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.cpp b/app/widget/timelinewidget/undo/timelineundogeneral.cpp index 63958f250..9c8bbae14 100644 --- a/app/widget/timelinewidget/undo/timelineundogeneral.cpp +++ b/app/widget/timelinewidget/undo/timelineundogeneral.cpp @@ -73,131 +73,121 @@ void BlockSetMediaInCommand::undo() // // TimelineAddTrackCommand // -TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks) +TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks) : + timeline_(timeline), + merge_(nullptr), + position_command_(nullptr) { - timeline_ = timeline; - position_command_ = nullptr; - + // Create new track track_ = new Track(); track_->setParent(&memory_manager_); - if (timeline->GetTrackCount() > 0 && automerge_tracks) { - if (timeline_->type() == Track::kVideo) { - merge_ = new MergeNode(); - base_ = NodeInput(merge_, MergeNode::kBaseIn); - blend_ = NodeInput(merge_, MergeNode::kBlendIn); - } else if (timeline_->type() == Track::kAudio) { - merge_ = new MathNode(); - base_ = NodeInput(merge_, MathNode::kParamAIn); - blend_ = NodeInput(merge_, MathNode::kParamBIn); - } else { - merge_ = nullptr; - } - } else { - merge_ = nullptr; + // Determine what input to connect it to + QString relevant_input; + + if (timeline_->type() == Track::kVideo) { + relevant_input = Sequence::kTextureInput; + } else if (timeline_->type() == Track::kAudio) { + relevant_input = Sequence::kSamplesInput; } - if (merge_) { - merge_->setParent(&memory_manager_); + // If we have an input to connect to, set it as our `direct` connection + if (!relevant_input.isEmpty()) { + direct_ = NodeInput(timeline_->parent(), relevant_input); + + // If we're automerging and something is already connected, determine if/how to merge it + if (automerge_tracks && direct_.IsConnected()) { + if (timeline_->type() == Track::kVideo) { + // Use merge for video + merge_ = new MergeNode(); + base_ = NodeInput(merge_, MergeNode::kBaseIn); + blend_ = NodeInput(merge_, MergeNode::kBlendIn); + } else if (timeline_->type() == Track::kAudio) { + // Use math (add) for audio + merge_ = new MathNode(); + base_ = NodeInput(merge_, MathNode::kParamAIn); + blend_ = NodeInput(merge_, MathNode::kParamBIn); + } + + if (merge_) { + // If we got created a merge node, ensure it's parented + merge_->setParent(&memory_manager_); + } + } } } void TimelineAddTrackCommand::redo() { - // Add track + // Get sequence + Sequence* sequence = timeline_->parent(); + + // Add track to sequence track_->setParent(timeline_->GetParentGraph()); timeline_->ArrayAppend(); Node::ConnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1)); + qreal position_factor = 0.5; + if (timeline_->type() == Track::kVideo) { + position_factor = -position_factor; + } + bool create_pos_command = (!position_command_ && (timeline_->type() == Track::kVideo || timeline_->type() == Track::kAudio)); + if (create_pos_command) { + position_command_ = new MultiUndoCommand(); + } + // Add merge if applicable - Track* last_track = nullptr; if (merge_) { + // Determine what was previously connected + Node *previous_connection = direct_.GetConnectedOutput(); + + // Add merge to graph merge_->setParent(timeline_->GetParentGraph()); - last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2); - - // Whatever this track used to be connected to, connect the merge instead - const Node::OutputConnections edges = last_track->output_connections(); - for (const Node::OutputConnection& ic : edges) { - const NodeInput& i = ic.second; - - // Ignore the track input, but funnel everything else through our merge - if (i.node() != timeline_->parent() || i.input() != timeline_->track_input()) { - Node::DisconnectEdge(last_track, i); - Node::ConnectEdge(merge_, i); - } - } - - // Connect this as the "blend" track + // Connect merge between what used to be here + Node::DisconnectEdge(previous_connection, direct_); + Node::ConnectEdge(merge_, direct_); + Node::ConnectEdge(previous_connection, base_); Node::ConnectEdge(track_, blend_); - Node::ConnectEdge(last_track, base_); - } else if (timeline_->GetTrackCount() == 1) { - // If this was the first track we added, - QString relevant_input; - if (timeline_->type() == Track::kVideo) { - relevant_input = ViewerOutput::kTextureInput; - } else if (timeline_->type() == Track::kAudio) { - relevant_input = ViewerOutput::kSamplesInput; + if (create_pos_command) { + position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, -position_factor))); + position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence))); + position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor * timeline_->GetTrackCount()), true)); } + } else if (direct_.IsValid() && !direct_.IsConnected()) { + // If no merge, we have a direct connection, and nothing else is connected, connect this + Node::ConnectEdge(track_, direct_); - if (!relevant_input.isEmpty() && !timeline_->parent()->IsInputConnected(relevant_input)) { - direct_ = NodeInput(timeline_->parent(), relevant_input); - - Node::ConnectEdge(track_, direct_); - } else { - direct_ = NodeInput(); + if (create_pos_command) { + // Just position directly next to the context node + position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor))); } } - // Position track in context - if (!position_command_) { - int track_count = timeline_->parent()->GetTracks().size(); - position_command_ = new MultiUndoCommand(); - - // Position either the merge or the track as an "element" - Node *node_to_position = merge_ ? merge_ : track_; - double node_index = track_count - 1; - if (merge_) { - node_index -= 1; - position_command_->add_child(new NodeRemovePositionFromContextCommand(last_track, timeline_->parent())); - } - - position_command_->add_child(new NodeSetPositionAsChildCommand(node_to_position, timeline_->parent(), timeline_->parent(), node_index, track_count, true)); - - // If we positioned a merge, position the tracks as children of the merge - if (merge_) { - // `last_track` should be non-null if `merge_` is non-null - position_command_->add_child(new NodeSetPositionAsChildCommand(last_track, merge_, timeline_->parent(), 0, 2, true)); - position_command_->add_child(new NodeSetPositionAsChildCommand(track_, merge_, timeline_->parent(), 1, 2, true)); - } + // Run position command if we created one + if (position_command_) { + position_command_->redo_now(); } - position_command_->redo_now(); } void TimelineAddTrackCommand::undo() { - position_command_->undo_now(); + if (position_command_) { + position_command_->undo_now(); + } // Remove merge if applicable if (merge_) { - // Assume whatever this merge is connected to USED to be connected to the last track - Track* last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2); + Node *previous_connection = base_.GetConnectedOutput(); Node::DisconnectEdge(track_, blend_); - Node::DisconnectEdge(last_track, base_); - - // Make copy of edges since the node's internal array will change as we disconnect things - const Node::OutputConnections edges = merge_->output_connections(); - for (const Node::OutputConnection& ic : edges) { - const NodeInput& i = ic.second; - - Node::DisconnectEdge(merge_, i); - Node::ConnectEdge(last_track, i); - } + Node::DisconnectEdge(previous_connection, base_); + Node::DisconnectEdge(merge_, direct_); + Node::ConnectEdge(previous_connection, direct_); merge_->setParent(&memory_manager_); - } else if (direct_.IsValid()) { + } else if (direct_.IsValid() && direct_.GetConnectedOutput() == track_) { Node::DisconnectEdge(track_, direct_); } @@ -496,11 +486,6 @@ void TrackReplaceBlockWithGapCommand::redo() our_gap_->setParent(track_->parent()); track_->ReplaceBlock(block_, our_gap_); - - if (!position_command_) { - position_command_ = new NodeSetPositionAsChildCommand(our_gap_, track_, track_, our_gap_->index(), track_->Blocks().size(), true); - } - position_command_->redo_now(); } track_->EndOperation(); @@ -533,8 +518,6 @@ void TrackReplaceBlockWithGapCommand::undo() track_->ReplaceBlock(our_gap_, block_); our_gap_->setParent(&memory_manager_); - position_command_->undo_now(); - } else { // If we're here, assume that we extended an existing gap diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.h b/app/widget/timelinewidget/undo/timelineundogeneral.h index 423f4da84..490d9b082 100644 --- a/app/widget/timelinewidget/undo/timelineundogeneral.h +++ b/app/widget/timelinewidget/undo/timelineundogeneral.h @@ -203,16 +203,10 @@ public: existing_gap_(nullptr), existing_merged_gap_(nullptr), our_gap_(nullptr), - handle_transitions_(handle_transitions), - position_command_(nullptr) + handle_transitions_(handle_transitions) { } - virtual ~TrackReplaceBlockWithGapCommand() override - { - delete position_command_; - } - virtual Project* GetRelevantProject() const override { return block_->project(); @@ -236,8 +230,6 @@ private: bool handle_transitions_; - NodeSetPositionAsChildCommand* position_command_; - QObject memory_manager_; QVector transition_remove_commands_; diff --git a/app/widget/timelinewidget/undo/timelineundopointer.cpp b/app/widget/timelinewidget/undo/timelineundopointer.cpp index 4f5c448b6..0f6501b19 100644 --- a/app/widget/timelinewidget/undo/timelineundopointer.cpp +++ b/app/widget/timelinewidget/undo/timelineundopointer.cpp @@ -324,7 +324,6 @@ TrackPlaceBlockCommand::~TrackPlaceBlockCommand() { delete ripple_remove_command_; qDeleteAll(add_track_commands_); - qDeleteAll(position_commands_); } void TrackPlaceBlockCommand::redo() @@ -367,14 +366,6 @@ void TrackPlaceBlockCommand::redo() } track->AppendBlock(insert_); - - if (position_commands_.isEmpty()) { - // Create position commands for insert and gap if necessary - if (gap_) { - position_commands_.append(new NodeSetPositionAsChildCommand(gap_, track, track, gap_->index(), track->Blocks().size(), true)); - } - position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true)); - } } else { // Place the Block at this point if (!ripple_remove_command_) { @@ -384,10 +375,6 @@ void TrackPlaceBlockCommand::redo() ripple_remove_command_->redo_now(); track->InsertBlockAfter(insert_, ripple_remove_command_->GetInsertionIndex()); - - if (position_commands_.isEmpty()) { - position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true)); - } } track->EndOperation(); @@ -397,18 +384,10 @@ void TrackPlaceBlockCommand::redo() foreach (const TimeRange &r, ranges_to_invalidate) { track->Node::InvalidateCache(r, Track::kBlockInput); } - - for (int i=0; iredo_now(); - } } void TrackPlaceBlockCommand::undo() { - for (int i=position_commands_.size()-1; i>=0; i--) { - position_commands_.at(i)->undo_now(); - } - Track* t = timeline_->GetTrackAt(track_index_); TimeRange insert_range(insert_->in(), insert_->out()); diff --git a/app/widget/timelinewidget/undo/timelineundopointer.h b/app/widget/timelinewidget/undo/timelineundopointer.h index fc7cf6566..4483d81d2 100644 --- a/app/widget/timelinewidget/undo/timelineundopointer.h +++ b/app/widget/timelinewidget/undo/timelineundopointer.h @@ -198,7 +198,6 @@ private: QVector add_track_commands_; QObject memory_manager_; TrackRippleRemoveAreaCommand* ripple_remove_command_; - QVector position_commands_; }; diff --git a/app/widget/timelinewidget/undo/timelineundosplit.cpp b/app/widget/timelinewidget/undo/timelineundosplit.cpp index 05c3b2707..06cdd1006 100644 --- a/app/widget/timelinewidget/undo/timelineundosplit.cpp +++ b/app/widget/timelinewidget/undo/timelineundosplit.cpp @@ -61,12 +61,6 @@ void BlockSplitCommand::redo() // Insert new block track->InsertBlockAfter(new_block(), block_); - // Position the block - if (!position_command_) { - position_command_ = new NodeSetPositionAsChildCommand(new_block(), track, track, new_block()->index(), track->Blocks().size(), true); - } - position_command_->redo_now(); - // If the block had an out transition, we move it to the new block moved_transition_ = NodeInput(); @@ -96,8 +90,6 @@ void BlockSplitCommand::undo() Node::ConnectEdge(block_, moved_transition_); } - position_command_->undo_now(); - block_->set_length_and_media_out(old_length_); track->RippleRemoveBlock(new_block()); diff --git a/app/widget/timelinewidget/undo/timelineundosplit.h b/app/widget/timelinewidget/undo/timelineundosplit.h index 82b57ebca..6984377f8 100644 --- a/app/widget/timelinewidget/undo/timelineundosplit.h +++ b/app/widget/timelinewidget/undo/timelineundosplit.h @@ -31,15 +31,13 @@ public: block_(block), new_block_(nullptr), point_(point), - reconnect_tree_command_(nullptr), - position_command_(nullptr) + reconnect_tree_command_(nullptr) { } virtual ~BlockSplitCommand() override { delete reconnect_tree_command_; - delete position_command_; } virtual Project* GetRelevantProject() const override @@ -70,8 +68,6 @@ private: NodeInput moved_transition_; - NodeSetPositionAsChildCommand* position_command_; - }; class BlockSplitPreservingLinksCommand : public UndoCommand { diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 8f1ace9ef..47c23c3cb 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -378,9 +378,7 @@ void MainWindow::ProjectClose(Project *p) } // Close project from NodeView - if (node_panel_->GetGraph() == p) { - node_panel_->ClearGraph(); - } + node_panel_->CloseContextsBelongingToProject(p); } void MainWindow::SetApplicationProgressStatus(ProgressStatus status) @@ -731,11 +729,7 @@ void MainWindow::UpdateNodePanelContextFromTimelinePanel(TimelinePanel *panel) context.append(viewer); } - QVector old_contexts = node_panel_->GetCurrentContexts(); - node_panel_->SetGraph(viewer ? viewer->parent() : nullptr, context); - if (viewer && context != old_contexts) { - node_panel_->SelectAll(); - } + node_panel_->SetContexts(context); } void MainWindow::FocusedPanelChanged(PanelWidget *panel) @@ -753,10 +747,6 @@ void MainWindow::FocusedPanelChanged(PanelWidget *panel) } else if (ProjectPanel* project = dynamic_cast(panel)) { // Signal project panel focus UpdateTitle(); - if (Project *p = project->project()) { - node_panel_->SetGraph(p, {p->root()}); - node_panel_->Select({p->color_manager(), p->settings()}, true); - } } }