diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index bf38b81fd..457372456 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -44,6 +44,11 @@ void NodePanel::SetGraph(NodeGraph *graph) node_view_->SetGraph(graph); } +void NodePanel::DeleteSelected() +{ + node_view_->DeleteSelected(); +} + void NodePanel::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { diff --git a/app/panel/node/node.h b/app/panel/node/node.h index 5e6c4b646..2d26d5187 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -35,6 +35,8 @@ public: void SetGraph(NodeGraph* graph); + virtual void DeleteSelected() override; + protected: virtual void changeEvent(QEvent* e) override; diff --git a/app/widget/menu/menushared.cpp b/app/widget/menu/menushared.cpp index 59d271271..213c0eece 100644 --- a/app/widget/menu/menushared.cpp +++ b/app/widget/menu/menushared.cpp @@ -43,7 +43,7 @@ void MenuShared::Initialize() edit_paste_item_ = Menu::CreateItem(this, "paste", nullptr, nullptr, "Ctrl+V"); edit_paste_insert_item_ = Menu::CreateItem(this, "pasteinsert", nullptr, nullptr, "Ctrl+Shift+V"); edit_duplicate_item_ = Menu::CreateItem(this, "duplicate", nullptr, nullptr, "Ctrl+D"); - edit_delete_item_ = Menu::CreateItem(this, "delete", nullptr, nullptr, "Del"); + edit_delete_item_ = Menu::CreateItem(this, "delete", this, SLOT(DeleteSelected()), "Del"); edit_ripple_delete_item_ = Menu::CreateItem(this, "rippledelete", nullptr, nullptr, "Shift+Del"); edit_split_item_ = Menu::CreateItem(this, "split", this, SLOT(SplitAtPlayhead()), "Ctrl+K"); @@ -110,6 +110,11 @@ void MenuShared::SplitAtPlayhead() } } +void MenuShared::DeleteSelected() +{ + olive::panel_manager->CurrentlyFocused()->DeleteSelected(); +} + void MenuShared::Retranslate() { // "New" menu shared items diff --git a/app/widget/menu/menushared.h b/app/widget/menu/menushared.h index 4e91f7cc2..6a172debb 100644 --- a/app/widget/menu/menushared.h +++ b/app/widget/menu/menushared.h @@ -71,6 +71,8 @@ private: private slots: void SplitAtPlayhead(); + void DeleteSelected(); + }; namespace olive { diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 78840e8ba..863cb7957 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -20,7 +20,9 @@ #include "nodeview.h" +#include "nodeviewundo.h" #include "node/factory.h" +#include "undo/undostack.h" NodeView::NodeView(QWidget *parent) : QGraphicsView(parent), @@ -119,6 +121,30 @@ NodeViewEdge *NodeView::EdgeToUIObject(NodeEdgePtr n) return EdgeToUIObject(&scene_, n); } +void NodeView::DeleteSelected() +{ + if (!graph_) { + return; + } + + QList selected = scene_.selectedItems(); + QList selected_nodes; + + foreach (QGraphicsItem* item, selected) { + NodeViewItem* node_item = dynamic_cast(item); + + if (node_item) { + selected_nodes.append(node_item->node()); + } + } + + if (selected_nodes.isEmpty()) { + return; + } + + olive::undo_stack.push(new NodeRemoveCommand(graph_, selected_nodes)); +} + void NodeView::AddNode(Node* node) { NodeViewItem* item = new NodeViewItem(); @@ -218,6 +244,6 @@ void NodeView::CreateNodeSlot(QAction *action) Node* new_node = NodeFactory::CreateFromMenuAction(action); if (new_node) { - graph_->AddNode(new_node); + olive::undo_stack.push(new NodeAddCommand(graph_, new_node)); } } diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index c3a719694..e186316e3 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -76,6 +76,11 @@ public: */ NodeViewEdge* EdgeToUIObject(NodeEdgePtr n); + /** + * @brief Delete selected nodes from graph (user-friendly/undoable) + */ + void DeleteSelected(); + signals: /** * @brief Signal emitted when the selected nodes have changed diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 4e61e422a..7d522cdd0 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -64,3 +64,64 @@ void NodeEdgeRemoveCommand::undo() NodeParam::ConnectEdge(output_, input_); done_ = false; } + +NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node, QUndoCommand *parent) : + QUndoCommand(parent), + graph_(graph), + node_(node) +{ + // Ensures that when this command is destroyed, if redo() hasn't been called, the node will be destroyed too + node->setParent(&memory_manager_); +} + +void NodeAddCommand::redo() +{ + graph_->AddNode(node_); +} + +void NodeAddCommand::undo() +{ + graph_->TakeNode(node_, &memory_manager_); +} + +NodeRemoveCommand::NodeRemoveCommand(NodeGraph *graph, const QList &nodes, QUndoCommand *parent) : + QUndoCommand(parent), + graph_(graph), + nodes_(nodes) +{ +} + +void NodeRemoveCommand::redo() +{ + // Cache edges for undoing + foreach (Node* n, nodes_) { + foreach (NodeParam* param, n->parameters()) { + foreach (NodeEdgePtr edge, param->edges()) { + // Ensures the same edge isn't added twice (prevents double connecting when undoing) + if (!edges_.contains(edge)) { + edges_.append(edge); + } + } + } + } + + // Take nodes from graph (TakeNode() will automatically disconnect edges) + foreach (Node* n, nodes_) { + graph_->TakeNode(n, &memory_manager_); + } +} + +void NodeRemoveCommand::undo() +{ + // Re-add nodes to graph + foreach (Node* n, nodes_) { + graph_->AddNode(n); + } + + // Re-connect edges + foreach (NodeEdgePtr edge, edges_) { + NodeParam::ConnectEdge(edge->output(), edge->input()); + } + + edges_.clear(); +} diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 6376dd986..77457da5c 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -3,6 +3,7 @@ #include +#include "node/graph.h" #include "node/node.h" /** @@ -45,4 +46,33 @@ private: bool done_; }; +class NodeAddCommand : public QUndoCommand { +public: + NodeAddCommand(NodeGraph* graph, Node* node, QUndoCommand* parent = nullptr); + + virtual void redo() override; + virtual void undo() override; + +private: + QObject memory_manager_; + + NodeGraph* graph_; + Node* node_; +}; + +class NodeRemoveCommand : public QUndoCommand { +public: + NodeRemoveCommand(NodeGraph* graph, const QList& nodes, QUndoCommand* parent = nullptr); + + virtual void redo() override; + virtual void undo() override; + +private: + QObject memory_manager_; + + NodeGraph* graph_; + QList nodes_; + QList edges_; +}; + #endif // NODEVIEWUNDO_H diff --git a/app/widget/panel/panel.h b/app/widget/panel/panel.h index febd14583..231cdc79d 100644 --- a/app/widget/panel/panel.h +++ b/app/widget/panel/panel.h @@ -106,6 +106,8 @@ public: virtual void GoToNextCut(){} + virtual void DeleteSelected(){} + protected: /** * @brief Set panel's title