diff --git a/app/node/node.h b/app/node/node.h index f8ef73fa7..4f45277d6 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -104,6 +104,11 @@ public: kAudioEffect = 0x4 }; + struct ContextPair { + Node *node; + Node *context; + }; + Node(); virtual ~Node() override; diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 5e694867b..d618c7d80 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -28,9 +28,10 @@ NodePanel::NodePanel(QWidget *parent) : node_widget_ = new NodeWidget(); connect(this, &NodePanel::visibilityChanged, node_widget_->view(), &NodeView::CenterOnItemsBoundingRect); - // Connect node view signals to this panel - MAY REMOVE connect(node_widget_->view(), &NodeView::NodesSelected, this, &NodePanel::NodesSelected); connect(node_widget_->view(), &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected); + connect(node_widget_->view(), &NodeView::NodeSelectionChanged, this, &NodePanel::NodeSelectionChanged); + connect(node_widget_->view(), &NodeView::NodeSelectionChangedWithContexts, this, &NodePanel::NodeSelectionChangedWithContexts); connect(node_widget_->view(), &NodeView::NodeGroupOpened, this, &NodePanel::NodeGroupOpened); connect(node_widget_->view(), &NodeView::NodeGroupClosed, this, &NodePanel::NodeGroupClosed); diff --git a/app/panel/node/node.h b/app/panel/node/node.h index b9a5ebf35..c8ebccaaa 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -105,10 +105,9 @@ public: } public slots: - void Select(const QVector& nodes, bool center_view_on_item) + void Select(const QVector &p) { - node_widget_->view()->Select(nodes, center_view_on_item); - this->raise(); + node_widget_->view()->Select(p, true); } signals: @@ -116,6 +115,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 8504a86b4..368a6abd2 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -28,24 +28,14 @@ ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) { NodeParamView* view = new NodeParamView(); - connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode); connect(view, &NodeParamView::FocusedNodeChanged, this, &ParamPanel::FocusedNodeChanged); + connect(view, &NodeParamView::SelectedNodesChanged, this, &ParamPanel::SelectedNodesChanged); connect(this, &ParamPanel::visibilityChanged, view, &NodeParamView::UpdateElementY); SetTimeBasedWidget(view); Retranslate(); } -void ParamPanel::SelectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->SelectNodes(nodes); -} - -void ParamPanel::DeselectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); -} - void ParamPanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 25b50a2db..9cfb881c0 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -49,8 +49,10 @@ public: } public slots: - void SelectNodes(const QVector& nodes); - void DeselectNodes(const QVector& nodes); + void SetSelectedNodes(const QVector &nodes) + { + GetParamView()->SetSelectedNodes(nodes, false); + } virtual void DeleteSelected() override; @@ -61,10 +63,10 @@ public slots: void SetContexts(const QVector &contexts); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void Retranslate() override; diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index f812c121e..2f97d8133 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -155,10 +155,11 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : SetScale(120); // Pickup on widget focus changes - connect(qApp, + // DISABLED - we now just handle this with item/titlebar clicking (see ToggleSelect) + /*connect(qApp, &QApplication::focusChanged, this, - &NodeParamView::FocusChanged); + &NodeParamView::FocusChanged);*/ } NodeParamView::~NodeParamView() @@ -297,12 +298,25 @@ void NodeParamView::ItemAboutToBeRemoved(NodeParamViewItem *item) } } - if (focused_node_ == item) { - focused_node_ = nullptr; - emit FocusedNodeChanged(nullptr); + QVector copy = selected_nodes_; + if (copy.removeOne(item)) { + SetSelectedNodes(copy); } } +void NodeParamView::ItemClicked() +{ + ToggleSelect(static_cast(sender())); +} + +void NodeParamView::SelectNodeFromConnectedLink(Node *node) +{ + NodeParamViewItem *item = static_cast(sender()); + + Node::ContextPair p = {node, item->GetContext()}; + SetSelectedNodes({p}); +} + void NodeParamView::SetContexts(const QVector &contexts) { // Setting contexts is expensive, so we queue it here to prevent multiple calls in a short timespan @@ -371,41 +385,138 @@ Node *NodeParamView::GetTimeTarget() const return time_target_; } +void ReconnectOutputsIfNotDeletingNode(MultiUndoCommand *c, NodeViewDeleteCommand *dc, Node *output, Node *deleting, Node *context) +{ + for (auto it=deleting->output_connections().cbegin(); it!=deleting->output_connections().cend(); it++) { + const NodeInput &proposed_reconnect = it->second; + + if (dc->ContainsNode(proposed_reconnect.node(), context)) { + // Uh-oh we're deleting this node too, instead connect to its outputs + ReconnectOutputsIfNotDeletingNode(c, dc, output, proposed_reconnect.node(), context); + } else { + c->add_child(new NodeEdgeAddCommand(output, it->second)); + } + } +} + void NodeParamView::DeleteSelected() { if (keyframe_view_ && keyframe_view_->hasFocus()) { keyframe_view_->DeleteSelected(); - } else if (focused_node_) { + } else if (!selected_nodes_.isEmpty()) { MultiUndoCommand *c = new MultiUndoCommand(); - Node *n = focused_node_->GetNode(); // Create command to delete node from context and/or graph NodeViewDeleteCommand *dc = new NodeViewDeleteCommand(); - dc->AddNode(n, focused_node_->GetContext()); c->add_child(dc); - // Copy any outputs that were connected - if (n->GetEffectInput().IsValid()) { - if (Node *out = n->GetEffectInput().GetConnectedOutput()) { - for (auto it=n->output_connections().cbegin(); it!=n->output_connections().cend(); it++) { - c->add_child(new NodeEdgeAddCommand(out, it->second)); - } - } + // Add all nodes + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + dc->AddNode(n, item->GetContext()); } + // Make reconnections where possible + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + + Node *node_being_deleted = n; + Node *connected_to_effect_input = n; + + while (true) { + if (node_being_deleted->GetEffectInput().IsValid()) { + if ((connected_to_effect_input = node_being_deleted->GetEffectInput().GetConnectedOutput())) { + if (dc->ContainsNode(connected_to_effect_input, item->GetContext())) { + // Node's getting deleted, recurse + node_being_deleted = connected_to_effect_input; + continue; + } + } + } + + break; + } + + if (connected_to_effect_input) { + ReconnectOutputsIfNotDeletingNode(c, dc, connected_to_effect_input, n, item->GetContext()); + } + } Core::instance()->undo_stack()->push(c); } } -void NodeParamView::SelectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool handle_focused_node, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + if (handle_focused_node) { + handle_focused_node = !focused_node_ || selected_nodes_.contains(focused_node_); + } + + foreach (NodeParamViewItem *n, selected_nodes_) { + n->SetHighlighted(false); + } + + selected_nodes_ = nodes; + + QVector p; + if (emit_signal) { + p.resize(selected_nodes_.size()); + } + + for (int i=0; iSetHighlighted(true); + + if (emit_signal) { + p[i] = {n->GetNode(), n->GetContext()}; + } + } + + if (handle_focused_node) { + focused_node_ = nullptr; + + foreach (NodeParamViewItem *n, selected_nodes_) { + if (n->GetNode()->HasGizmos()) { + focused_node_ = n; + break; + } + } + + Node *n = focused_node_ ? focused_node_->GetNode() : nullptr; + emit FocusedNodeChanged(n); + } + + if (emit_signal) { + emit SelectedNodesChanged(p); + } } -void NodeParamView::DeselectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + QVector items; + + foreach (const Node::ContextPair &n, nodes) { + for (auto it=context_items_.cbegin(); it!=context_items_.cend(); it++) { + NodeParamViewContext *ctx = *it; + + NodeParamViewItem *item = ctx->GetItem(n.node, n.context); + + if (item) { + items.append(item); + } + } + } + + SetSelectedNodes(items, true, emit_signal); + + if (!selected_nodes_.empty()) { + NodeParamViewItem *scrolled_to = selected_nodes_.front(); + param_scroll_area_->ensureWidgetVisible(scrolled_to, 0, 0); + + QPoint viewport_pos = scrolled_to->mapTo(param_scroll_area_, scrolled_to->geometry().topLeft()); + + param_scroll_area_->verticalScrollBar()->setValue(viewport_pos.y()); + } } void NodeParamView::UpdateItemTime(const rational &time) @@ -461,9 +572,10 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) NodeParamViewItem* item = new NodeParamViewItem(n, IsGroupMode() ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context); connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal); - connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode); + connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::SelectNodeFromConnectedLink); connect(item, &NodeParamViewItem::PinToggled, this, &NodeParamView::PinNode); connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::InputCheckBoxChanged); + connect(item, &NodeParamViewItem::Clicked, this, &NodeParamView::ItemClicked); item->SetContext(ctx); item->SetTimeTarget(GetTimeTarget()); @@ -474,9 +586,7 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) if (!focused_node_ && n->HasGizmos()) { // We'll focus this node now - item->SetHighlighted(true); - focused_node_ = item; - emit FocusedNodeChanged(n); + SetSelectedNodes({item}); } if (keyframe_view_) { @@ -561,6 +671,36 @@ NodeParamViewContext *NodeParamView::GetContextItemFromContext(Node *ctx) return context_items_.at(ctx_type); } +void NodeParamView::ToggleSelect(NodeParamViewItem *item) +{ + QVector new_sel; + + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel = selected_nodes_; + } + + if (selected_nodes_.contains(item)) { + // De-select this node + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel.removeOne(item); + SetSelectedNodes(new_sel, true); + } + } else { + new_sel.append(item); + SetSelectedNodes(new_sel, false); + + if (item->GetNode()->HasGizmos() || !new_sel.contains(focused_node_)) { + if (item->GetNode()->HasGizmos()) { + focused_node_ = item; + } else { + focused_node_ = nullptr; + } + + emit FocusedNodeChanged(focused_node_ ? focused_node_->GetNode() : nullptr); + } + } +} + void NodeParamView::UpdateGlobalScrollBar() { if (keyframe_view_) { @@ -584,7 +724,7 @@ void NodeParamView::PinNode(bool pin) } } -void NodeParamView::FocusChanged(QWidget* old, QWidget* now) +/*void NodeParamView::FocusChanged(QWidget* old, QWidget* now) { Q_UNUSED(old) @@ -592,39 +732,28 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now) while (parent) { if (NodeParamViewItem* item = dynamic_cast(parent)) { - if (item != focused_node_) { - // Found a NodeParamViewItem that isn't already focused, see if it belongs to us - bool ours = false; + // Found a NodeParamViewItem that isn't already focused, see if it belongs to us + bool ours = false; - do { - parent = parent->parent(); + do { + parent = parent->parent(); - if (parent == this) { - ours = true; - break; - } - } while (parent); - - if (ours) { - // This item is ours, - if (focused_node_) { - // De-focus current node - focused_node_->SetHighlighted(false); - } - - focused_node_ = item; - - item->SetHighlighted(true); - - emit FocusedNodeChanged(item->GetNode()); + if (parent == this) { + ours = true; + break; } + } while (parent); + + if (ours) { + //ToggleSelect(item); + Q_UNUSED(item) } break; } parent = parent->parent(); } -} +}*/ void NodeParamView::KeyframeViewDragged(int x, int y) { diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index f04072e52..3b90e22b7 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -61,8 +61,8 @@ public: keyframe_view_->DeselectAll(); } - void SelectNodes(const QVector &nodes); - void DeselectNodes(const QVector &nodes); + void SetSelectedNodes(const QVector &nodes, bool handle_focused_node = true, bool emit_signal = true); + void SetSelectedNodes(const QVector &nodes, bool emit_signal = true); const QVector &GetContexts() const { @@ -75,10 +75,10 @@ public slots: void UpdateElementY(); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -118,6 +118,8 @@ private: return contexts_.size() == 1 && dynamic_cast(contexts_.first()); } + void ToggleSelect(NodeParamViewItem *item); + KeyframeView* keyframe_view_; QVector context_items_; @@ -137,6 +139,7 @@ private: QVector active_nodes_; NodeParamViewItem* focused_node_; + QVector selected_nodes_; Node *time_target_; @@ -150,7 +153,7 @@ private slots: void PinNode(bool pin); - void FocusChanged(QWidget *old, QWidget *now); + //void FocusChanged(QWidget *old, QWidget *now); void KeyframeViewDragged(int x, int y); @@ -168,6 +171,10 @@ private slots: void ItemAboutToBeRemoved(NodeParamViewItem *item); + void ItemClicked(); + + void SelectNodeFromConnectedLink(Node *node); + }; } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp index 2810113a1..d55fbe103 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp @@ -135,7 +135,7 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu() void NodeParamViewConnectedLabel::ConnectionClicked() { if (connected_node_) { - emit RequestSelectNode({connected_node_}); + emit RequestSelectNode(connected_node_); } } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h index 621a697e1..3e4fc5f55 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h @@ -35,7 +35,7 @@ public: void SetTime(const rational &time); signals: - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *n); private slots: void InputConnected(Node *output, const NodeInput &input); diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 95ee238d8..3db8692a1 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -67,7 +67,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); @@ -214,7 +214,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); diff --git a/app/widget/nodeparamview/nodeparamviewitembase.cpp b/app/widget/nodeparamview/nodeparamviewitembase.cpp index f29d70702..645ee79f1 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.cpp +++ b/app/widget/nodeparamview/nodeparamviewitembase.cpp @@ -40,6 +40,7 @@ NodeParamViewItemBase::NodeParamViewItemBase(QWidget *parent) : // Connect title bar to this connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItemBase::SetExpanded); connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItemBase::PinToggled); + connect(title_bar_, &NodeParamViewItemTitleBar::Clicked, this, &NodeParamViewItemBase::Clicked); // Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar // size hints and will shrink as small as possible if the body is hidden) @@ -115,4 +116,11 @@ void NodeParamViewItemBase::moveEvent(QMoveEvent *event) emit Moved(); } +void NodeParamViewItemBase::mousePressEvent(QMouseEvent *e) +{ + super::mousePressEvent(e); + + emit Clicked(); +} + } diff --git a/app/widget/nodeparamview/nodeparamviewitembase.h b/app/widget/nodeparamview/nodeparamviewitembase.h index d5f570656..a728bb93f 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.h +++ b/app/widget/nodeparamview/nodeparamviewitembase.h @@ -60,6 +60,8 @@ signals: void Moved(); + void Clicked(); + protected: void SetBody(QWidget *body); @@ -74,6 +76,8 @@ protected: virtual void moveEvent(QMoveEvent *event) override; + virtual void mousePressEvent(QMouseEvent *e) override; + protected slots: virtual void Retranslate(){} diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp index 1d79ff4d9..efe3d2768 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp @@ -85,6 +85,13 @@ void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) } } +void NodeParamViewItemTitleBar::mousePressEvent(QMouseEvent *event) +{ + QWidget::mousePressEvent(event); + + emit Clicked(); +} + void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event) { QWidget::mouseDoubleClickEvent(event); diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h index 9bea7f06f..7024c9e82 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h @@ -79,9 +79,12 @@ signals: void EnabledCheckBoxClicked(bool e); + void Clicked(); + protected: virtual void paintEvent(QPaintEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseDoubleClickEvent(QMouseEvent *event) override; private: diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 07251995d..220a040bf 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -51,7 +51,8 @@ NodeView::NodeView(QWidget *parent) : create_edge_output_item_(nullptr), create_edge_input_item_(nullptr), overlay_view_(nullptr), - scale_(1.0) + scale_(1.0), + dont_emit_selection_signals_(false) { setScene(&scene_); SetDefaultDragMode(RubberBandDrag); @@ -171,9 +172,11 @@ void NodeView::DeselectAll() // Just emit all the nodes that are currently selected as no longer selected emit NodesDeselected(selected_nodes_); selected_nodes_.clear(); + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(QVector()); } -void NodeView::Select(const QVector &nodes, bool center_view_on_item) +void NodeView::Select(const QVector &nodes, bool center_view_on_item) { // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. @@ -184,18 +187,27 @@ void NodeView::Select(const QVector &nodes, bool center_view_on_item) scene_.DeselectAll(); - foreach (NodeViewContext *context, scene_.context_map()) { - context->Select(nodes); + foreach (const Node::ContextPair &p, nodes) { + NodeViewContext *ctx = scene_.context_map().value(p.context); + if (ctx) { + NodeViewItem *item = ctx->GetItemFromMap(p.node); + if (item) { + item->setSelected(true); + } + } } // Center on something if (center_view_on_item && !nodes.isEmpty()) { - QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first())); + QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first().node)); } ConnectSelectionChangedSignal(); + // Don't signal when this function was likely triggered from another widget's signal anyway + dont_emit_selection_signals_ = true; UpdateSelectionCache(); + dont_emit_selection_signals_ = false; } void NodeView::CopySelected(bool cut) @@ -734,13 +746,18 @@ void NodeView::UpdateSelectionCache() QVector selected; QVector deselected; + QVector sel_with_ctx(current_selection.size()); + // Determine which nodes are newly selected - foreach (NodeViewItem* i, current_selection) { + for (int j=0; jGetNode(); if (!selected_nodes_.contains(n)) { selected.append(n); selected_nodes_.append(n); } + + sel_with_ctx[j] = {n, i->GetContext()}; } // Determine which nodes are newly deselected @@ -773,6 +790,11 @@ void NodeView::UpdateSelectionCache() if (!selected.isEmpty()) { emit NodesSelected(selected); } + + if (!dont_emit_selection_signals_) { + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(sel_with_ctx); + } } void NodeView::ShowContextMenu(const QPoint &pos) @@ -1344,6 +1366,8 @@ void NodeView::ShowNodeProperties() overlay_view_->setFocus(); emit NodesDeselected(selected_nodes_); + emit NodeSelectionChanged(QVector()); + emit NodeSelectionChangedWithContexts(QVector()); overlay_view_->SelectAll(); emit NodeGroupOpened(group); diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 26894511e..d18d2d185 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -77,7 +77,7 @@ public: void SelectAll(); void DeselectAll(); - void Select(const QVector &nodes, bool center_view_on_item); + void Select(const QVector &nodes, bool center_view_on_item); void CopySelected(bool cut); void Paste(); @@ -117,6 +117,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); @@ -218,6 +221,8 @@ private: double scale_; + bool dont_emit_selection_signals_; + static const double kMinimumScale; private slots: diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 54106070f..2ed0ef28b 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -199,13 +199,12 @@ NodeViewDeleteCommand::NodeViewDeleteCommand() void NodeViewDeleteCommand::AddNode(Node *node, Node *context) { - foreach (const NodePair &pair, nodes_) { - if (pair.first == node && pair.second == context) { - return; - } + if (ContainsNode(node, context)) { + return; } - nodes_.append(NodePair({node, context})); + Node::ContextPair p = {node, context}; + nodes_.append(p); for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { if (context->ContextContainsNode(it->second)) { @@ -231,10 +230,21 @@ void NodeViewDeleteCommand::AddEdge(Node *output, const NodeInput &input) edges_.append({output, input}); } +bool NodeViewDeleteCommand::ContainsNode(Node *node, Node *context) +{ + foreach (const Node::ContextPair &pair, nodes_) { + if (pair.node == node && pair.context == context) { + return true; + } + } + + return false; +} + Project *NodeViewDeleteCommand::GetRelevantProject() const { if (!nodes_.isEmpty()) { - return nodes_.first().first->project(); + return nodes_.first().node->project(); } if (!edges_.isEmpty()) { @@ -250,11 +260,11 @@ void NodeViewDeleteCommand::redo() Node::DisconnectEdge(edge.first, edge.second); } - foreach (const NodePair &pair, nodes_) { + foreach (const Node::ContextPair &pair, nodes_) { RemovedNode rn; - rn.node = pair.first; - rn.context = pair.second; + rn.node = pair.node; + rn.context = pair.context; rn.pos = rn.context->GetNodePositionInContext(rn.node); rn.context->RemoveNodeFromContext(rn.node); diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 567198b5b..bb4588444 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -372,6 +372,8 @@ public: void AddEdge(Node *output, const NodeInput &input); + bool ContainsNode(Node *node, Node *context); + virtual Project * GetRelevantProject() const override; protected: @@ -380,9 +382,7 @@ protected: virtual void undo() override; private: - using NodePair = QPair; - - QVector nodes_; + QVector nodes_; QVector edges_; diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 8e247a76c..1bf868ffd 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -92,15 +92,12 @@ MainWindow::MainWindow(QWidget *parent) : scope_panel_ = new ScopePanel(this); // Make node-related connections - connect(node_panel_, &NodePanel::NodesSelected, param_panel_, &ParamPanel::SelectNodes); - connect(node_panel_, &NodePanel::NodesDeselected, param_panel_, &ParamPanel::DeselectNodes); + connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, param_panel_, &ParamPanel::SetSelectedNodes); connect(node_panel_, &NodePanel::NodeGroupOpened, this, &MainWindow::NodePanelGroupOpenedOrClosed); connect(node_panel_, &NodePanel::NodeGroupClosed, this, &MainWindow::NodePanelGroupOpenedOrClosed); - connect(param_panel_, &ParamPanel::RequestSelectNode, this, [this](const QVector& target){ - node_panel_->Select(target, true); - }); connect(param_panel_, &ParamPanel::FocusedNodeChanged, sequence_viewer_panel_, &ViewerPanel::SetGizmos); connect(param_panel_, &ParamPanel::FocusedNodeChanged, curve_panel_, &CurvePanel::SetNode); + connect(param_panel_, &ParamPanel::SelectedNodesChanged, node_panel_, &NodePanel::Select); // Connect time signals together connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime);