From 2a9513e56ab2b5e5eba49924c64d19c4932129ab Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 14 Mar 2021 21:09:00 +1100 Subject: [PATCH] added new node auto-positioning for items --- app/node/node.cpp | 44 ++++++- app/node/node.h | 140 ++++++++++++++++++++++- app/project/item/folder/folder.cpp | 20 +++- app/project/item/folder/folder.h | 4 + app/project/project.cpp | 4 + app/widget/timelinewidget/timelineundo.h | 16 ++- 6 files changed, 224 insertions(+), 4 deletions(-) diff --git a/app/node/node.cpp b/app/node/node.cpp index 486cb90c6..d4e6d9aea 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1803,11 +1803,20 @@ const QPointF &Node::GetPosition() const return position_; } -void Node::SetPosition(const QPointF &pos) +void Node::SetPosition(const QPointF &pos, bool move_dependencies_relatively_too) { position_ = pos; emit PositionChanged(position_); + + if (move_dependencies_relatively_too) { + QPointF difference = pos - GetPosition(); + + for (auto it=input_connections_.cbegin(); it!=input_connections_.cend(); it++) { + Node* c = it->second.node(); + c->SetPosition(c->GetPosition() + difference, true); + } + } } void Node::ParameterValueChanged(const QString& input, int element, const TimeRange& range) @@ -2252,4 +2261,37 @@ Project *Node::ArrayResizeCommand::GetRelevantProject() const return node_->project(); } +void NodeSetPositionAndShiftSurroundingsCommand::redo() +{ + if (commands_.isEmpty()) { + // Move first node + NodeSetPositionCommand* set_pos_command = new NodeSetPositionCommand(node_, position_, move_dependencies_); + set_pos_command->redo(); + commands_.append(set_pos_command); + + // Get bounding rect + QRectF bounding_rect(position_.x() - 0.5, position_.y() - 0.5, 1, 1); + + // Start moving other nodes + foreach (Node* surrounding, node_->parent()->nodes()) { + if (bounding_rect.contains(surrounding->GetPosition()) && surrounding != node_) { + QPointF new_pos = surrounding->GetPosition(); + if (surrounding->GetPosition().y() > position_.y()) { + new_pos.setY(new_pos.y() + 0.5); + } else { + new_pos.setY(new_pos.y() - 0.5); + } + + auto sur_command = new NodeSetPositionAndShiftSurroundingsCommand(surrounding, new_pos, true); + sur_command->redo(); + commands_.append(sur_command); + } + } + } else { + for (int i=0; iredo(); + } + } +} + } diff --git a/app/node/node.h b/app/node/node.h index 6c0d155f9..bc546f908 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -707,7 +707,7 @@ public: const QPointF& GetPosition() const; - void SetPosition(const QPointF& pos); + void SetPosition(const QPointF& pos, bool move_dependencies_relatively_too = false); virtual bool HasGizmos() const; @@ -1257,6 +1257,144 @@ QVector Node::FindOutputNode() using NodePtr = std::shared_ptr; +class NodeSetPositionCommand : public UndoCommand +{ +public: + NodeSetPositionCommand(Node* node, const QPointF& position, bool move_dependencies_relatively) : + node_(node), + new_pos_(position), + move_deps_(move_dependencies_relatively) + { + } + + virtual Project * GetRelevantProject() const override + { + return node_->project(); + } + + virtual void redo() override + { + old_pos_ = node_->GetPosition(); + node_->SetPosition(new_pos_, move_deps_); + } + + virtual void undo() override + { + node_->SetPosition(old_pos_, move_deps_); + } + +private: + Node* node_; + + QPointF new_pos_; + QPointF old_pos_; + + bool move_deps_; + +}; + +class NodeSetPositionAndShiftSurroundingsCommand : public UndoCommand +{ +public: + NodeSetPositionAndShiftSurroundingsCommand(Node* node, const QPointF& pos, bool move_dependencies_relatively) : + node_(node), + position_(pos), + move_dependencies_(move_dependencies_relatively) + {} + + virtual ~NodeSetPositionAndShiftSurroundingsCommand() override + { + qDeleteAll(commands_); + } + + virtual Project * GetRelevantProject() const override + { + return node_->project(); + } + + virtual void redo() override; + + virtual void undo() override + { + for (int i=commands_.size()-1; i>=0; i--) { + commands_.at(i)->undo(); + } + } + +private: + Node* node_; + + QPointF position_; + + bool move_dependencies_; + + QVector commands_; + +}; + +class NodeSetPositionAsChildCommand : public UndoCommand +{ +public: + NodeSetPositionAsChildCommand(Node* node, Node* parent, int this_index, int child_count, bool shift_surroundings) : + node_(node), + parent_(parent), + 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(); + } + + virtual void redo() override + { + if (!sub_command_) { + // Calculate position of node + QPointF pos = parent_->GetPosition(); + + // 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); + + if (shift_surroundings_) { + sub_command_ = new NodeSetPositionAndShiftSurroundingsCommand(node_, pos, true); + } else { + sub_command_ = new NodeSetPositionCommand(node_, pos, true); + } + } + + sub_command_->redo(); + } + + virtual void undo() override + { + sub_command_->undo(); + } + +private: + Node* node_; + Node* parent_; + + int this_index_; + int child_count_; + + bool shift_surroundings_; + + UndoCommand* sub_command_; + +}; + } #endif // NODE_H diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 6d9c5c9cf..cdb36801e 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -115,10 +115,16 @@ void Folder::InputDisconnectedEvent(const QString &input, int element, const Nod FolderAddChild::FolderAddChild(Folder *folder, Node *child, bool autoposition) : folder_(folder), child_(child), - autoposition_(autoposition) + autoposition_(autoposition), + position_command_(nullptr) { } +FolderAddChild::~FolderAddChild() +{ + delete position_command_; +} + Project *FolderAddChild::GetRelevantProject() const { return folder_->project(); @@ -129,10 +135,22 @@ 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_) { + old_position_ = child_->GetPosition(); + if (!position_command_) { + position_command_ = new NodeSetPositionAsChildCommand(child_, folder_, array_index, array_index+1, true); + } + position_command_->redo(); + } } void FolderAddChild::undo() { + if (position_command_) { + position_command_->undo(); + } + Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1)); folder_->InputArrayRemoveLast(Folder::kChildInput); } diff --git a/app/project/item/folder/folder.h b/app/project/item/folder/folder.h index 212112d16..8c3c2244d 100644 --- a/app/project/item/folder/folder.h +++ b/app/project/item/folder/folder.h @@ -160,6 +160,8 @@ class FolderAddChild : public UndoCommand public: FolderAddChild(Folder* folder, Node* child, bool autoposition = true); + virtual ~FolderAddChild() override; + virtual Project * GetRelevantProject() const override; virtual void redo() override; @@ -175,6 +177,8 @@ private: QPointF old_position_; + NodeSetPositionAsChildCommand* position_command_; + }; } diff --git a/app/project/project.cpp b/app/project/project.cpp index e42aa9039..3dfbde3c9 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -39,16 +39,20 @@ Project::Project() : // Adds a color manager "node" to this project so that it synchronizes color_manager_ = new ColorManager(); color_manager_->setParent(this); + color_manager_->SetPosition(QPointF(1, 0)); AddDefaultNode(color_manager_); // Same with project settings settings_ = new ProjectSettingsNode(); settings_->setParent(this); + settings_->SetPosition(QPointF(2, 0)); AddDefaultNode(settings_); // Viewer node for connecting with the footage viewer footage_viewer_ = new ViewerOutput(); footage_viewer_->setParent(this); + footage_viewer_->SetLabel(tr("Footage Viewer")); + footage_viewer_->SetPosition(QPointF(3, 0)); AddDefaultNode(footage_viewer_); // Folder root for project diff --git a/app/widget/timelinewidget/timelineundo.h b/app/widget/timelinewidget/timelineundo.h index 10dab5ef6..6ff13abdc 100644 --- a/app/widget/timelinewidget/timelineundo.h +++ b/app/widget/timelinewidget/timelineundo.h @@ -1309,7 +1309,8 @@ private: class TimelineAddTrackCommand : public UndoCommand { public: TimelineAddTrackCommand(TrackList *timeline) : - timeline_(timeline) + timeline_(timeline), + position_command_(nullptr) { track_ = new Track(); track_->setParent(&memory_manager_); @@ -1330,6 +1331,11 @@ public: } } + virtual ~TimelineAddTrackCommand() override + { + delete position_command_; + } + Track* track() const { return track_; @@ -1345,6 +1351,11 @@ public: // Add track track_->setParent(timeline_->GetParentGraph()); timeline_->ArrayAppend(); + int track_total_index = timeline_->parent()->GetTracks().size(); + if (!position_command_) { + position_command_ = new NodeSetPositionAsChildCommand(track_, timeline_->parent(), track_total_index, track_total_index + 1, true); + } + position_command_->redo(); Node::ConnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1)); // Add merge if applicable @@ -1414,6 +1425,7 @@ public: // Remove track Node::DisconnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1)); + position_command_->undo(); timeline_->ArrayRemoveLast(); track_->setParent(&memory_manager_); } @@ -1428,6 +1440,8 @@ private: NodeInput direct_; + NodeSetPositionAsChildCommand* position_command_; + QObject memory_manager_; };