From f9309da4b375f7d6cfce6ddd548bef63d7127d0f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 24 May 2021 10:12:53 +1000 Subject: [PATCH] nodeview: update positions correctly --- app/widget/nodeview/nodeview.cpp | 192 +++++++++++++++----------- app/widget/nodeview/nodeview.h | 9 ++ app/widget/nodeview/nodeviewitem.cpp | 11 +- app/widget/nodeview/nodeviewitem.h | 8 +- app/widget/nodeview/nodeviewscene.cpp | 7 + app/widget/nodeview/nodeviewscene.h | 5 + 6 files changed, 149 insertions(+), 83 deletions(-) diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 68ade78de..9f72a4246 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -20,6 +20,7 @@ #include "nodeview.h" +#include #include #include #include @@ -56,6 +57,7 @@ NodeView::NodeView(QWidget *parent) : setViewportUpdateMode(FullViewportUpdate); connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu); + connect(&scene_, &NodeViewScene::NodePositionChanged, this, &NodeView::NodePositionChanged); ConnectSelectionChangedSignal(); @@ -70,106 +72,120 @@ NodeView::~NodeView() void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes) { - // Handle potentially changing graph - if (graph_ != graph) { - if (graph_) { - disconnect(graph_, &NodeGraph::NodeAdded, this, &NodeView::AddNode); - 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); + bool graph_changed = graph_ != graph; + bool context_changed = filter_nodes_ != nodes; - if (filter_mode_ == kFilterShowAll) { - // Switching graphs, close all nodes - DeselectAll(); - scene_.clear(); - } - } + 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); - graph_ = graph; - - if (graph_) { - connect(graph_, &NodeGraph::NodeAdded, this, &NodeView::AddNode); - 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 (filter_mode_ == kFilterShowAll) { - foreach (Node* n, graph_->nodes()) { - scene_.AddNode(n); - } - - foreach (Node* n, graph_->nodes()) { - for (auto it=n->input_connections().cbegin(); it!=n->input_connections().cend(); it++) { - scene_.AddEdge(it->second, it->first); - } - } - } - } - } - - // Handle changing nodes - if (filter_nodes_ != nodes) { - filter_nodes_ = nodes; - - if (filter_mode_ == kFilterShowSelective) { + if (refresh_required) { DeselectAll(); + positions_.clear(); scene_.clear(); + } + + // Handle graph change + if (graph_changed) { + if (graph_) { + // Disconnect from current graph + disconnect(graph_, &NodeGraph::NodeAdded, this, &NodeView::AddNode); + 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::NodeAdded, this, &NodeView::AddNode); + 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) { + filter_nodes_ = nodes; + } + + if (refresh_required && nodes_visible) { QMap > averaged_positions; QPointF origin(0, 0); - foreach (void *n, filter_nodes_) { - const NodeGraph::PositionMap &map = graph_->GetNodesForRelative(n); + if (filter_mode_ == kFilterShowAll) { + // FIXME: Implement + } else { + // Reserve an arbitrary number to reduce the amount of reallocations + foreach (void *n, filter_nodes_) { + const NodeGraph::PositionMap &map = graph_->GetNodesForRelative(n); - qreal top = 0, bottom = 0; + qreal top = 0, bottom = 0; - for (auto it=map.cbegin(); it!=map.cend(); it++) { - NodeViewItem *item = scene_.item_map().value(it.key()); + for (auto it=map.cbegin(); it!=map.cend(); it++) { + // Determine position + NodeViewItem *item = scene_.item_map().value(it.key()); - if (item) { - QVector &averages = averaged_positions[item]; - if (averages.isEmpty()) { - averages.append(item->GetNodePosition()); + if (item) { + QVector &averages = averaged_positions[item]; + if (averages.isEmpty()) { + averages.append(item->GetNodePosition()); + } + averages.append(origin + it.value()); + } else { + item = scene_.AddNode(it.key()); } - averages.append(origin + it.value()); - } else { - item = scene_.AddNode(it.key()); + + const QPointF &pos = it.value(); + top = qMin(top, pos.y()); + bottom = qMax(bottom, pos.y()); + + item->SetNodePosition(origin + pos); } - const QPointF &pos = it.value(); - top = qMin(top, pos.y()); - bottom = qMax(bottom, pos.y()); - - item->SetNodePosition(origin + pos); + origin.setY(origin.y() + 1 + (bottom - top)); } - origin.setY(origin.y() + 1 + (bottom - top)); - } + for (auto it=averaged_positions.cbegin(); it!=averaged_positions.cend(); it++) { + const QVector &positions = it.value(); + double x = DBL_MAX; + double y = 0.0; - for (auto it=scene_.item_map().cbegin(); it!=scene_.item_map().cend(); it++) { - Node *node = it.key(); - for (auto jt=node->input_connections().cbegin(); jt!=node->input_connections().cend(); jt++) { - const NodeOutput &output = jt->second; - if (scene_.item_map().contains(output.node())) { - // Create edge since both input and output exist - scene_.AddEdge(output, jt->first); + // Min the X value and average the Y values + foreach (const QPointF &pos, positions) { + x = qMin(x, pos.x()); + y += pos.y(); } - } - } - for (auto it=averaged_positions.cbegin(); it!=averaged_positions.cend(); it++) { - const QVector &positions = it.value(); - QPointF p; - foreach (const QPointF &pos, positions) { - p += pos; + y /= positions.size(); + + it.key()->SetNodePosition(QPointF(x, y)); + } + + for (auto it=scene_.item_map().cbegin(); it!=scene_.item_map().cend(); it++) { + // Add edge objects + Node *node = it.key(); + for (auto jt=node->input_connections().cbegin(); jt!=node->input_connections().cend(); jt++) { + const NodeOutput &output = jt->second; + if (scene_.item_map().contains(output.node())) { + // Create edge since both input and output exist + scene_.AddEdge(output, jt->first); + } + } + + // Store view position + positions_.insert(it.value(), {it.key(), it.value()->GetNodePosition()}); } - p /= positions.size(); - it.key()->SetNodePosition(p); } } } @@ -983,7 +999,7 @@ void NodeView::RemoveEdge(const NodeOutput &output, const NodeInput &input) void NodeView::AddNodePosition(Node *node, void *relative, const QPointF &pos) { - if (filter_mode_ == kFilterShowSelective) { + /*if (filter_mode_ == kFilterShowSelective) { if (filter_nodes_.contains(relative)) { NodeViewItem *item = scene_.item_map().value(node); @@ -1003,7 +1019,7 @@ void NodeView::AddNodePosition(Node *node, void *relative, const QPointF &pos) item->SetNodePosition(pos); } - } + }*/ } void NodeView::RemoveNodePosition(Node *node, void *relative) @@ -1016,6 +1032,20 @@ void NodeView::RemoveNodePosition(Node *node, void *relative) } } +void NodeView::NodePositionChanged(NodeViewItem *item, const QPointF &pos) +{ + Position &original_pos = positions_[item]; + Node *node = original_pos.node; + QPointF diff = pos - original_pos.original_item_pos; + original_pos.original_item_pos = pos; + + foreach (void *context, filter_nodes_) { + QPointF p = graph_->GetNodePosition(node, context); + p += diff; + graph_->SetNodePosition(node, context, p); + } +} + void NodeView::AttachNodesToCursor(const QVector &nodes) { QVector items(nodes.size()); diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 05b0ca8a4..b832095c7 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -155,6 +155,13 @@ private: kFilterShowSelective }; + struct Position { + Node *node; + QPointF original_item_pos; + }; + + QMap positions_; + FilterMode filter_mode_; QVector filter_nodes_; @@ -209,6 +216,8 @@ private slots: void AddNodePosition(Node *node, void *relative, const QPointF &pos); void RemoveNodePosition(Node *node, void *relative); + void NodePositionChanged(NodeViewItem *item, const QPointF &pos); + }; } diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 7e43e1f6b..31ad78cf7 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -45,7 +45,8 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) : expanded_(false), hide_titlebar_(false), highlighted_index_(-1), - flow_dir_(NodeViewCommon::kLeftToRight) + flow_dir_(NodeViewCommon::kLeftToRight), + dont_signal_(false) { // Set flags for this widget setFlag(QGraphicsItem::ItemIsMovable); @@ -336,6 +337,10 @@ QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons { if (change == ItemPositionHasChanged && node_) { ReadjustAllEdges(); + + if (!dont_signal_) { + emit NodePositionChanged(GetNodePosition()); + } } return QGraphicsItem::itemChange(change, value); @@ -479,6 +484,8 @@ QPointF NodeViewItem::GetInputPointInternal(int index, const QPointF& source_pos void NodeViewItem::UpdateNodePosition() { + dont_signal_ = true; + const QPointF &pos = cached_node_pos_; switch (flow_dir_) { @@ -499,6 +506,8 @@ void NodeViewItem::UpdateNodePosition() -pos.x() * DefaultItemVerticalPadding()); break; } + + dont_signal_ = false; } } diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 1edab3aa5..854de5e6c 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -40,8 +40,9 @@ class NodeViewEdge; * * To retrieve the NodeViewItem for a certain Node, use NodeView::NodeToUIObject(). */ -class NodeViewItem : public QGraphicsRectItem +class NodeViewItem : public QObject, public QGraphicsRectItem { + Q_OBJECT public: NodeViewItem(QGraphicsItem* parent = nullptr); @@ -111,6 +112,9 @@ public: void SetHighlightedIndex(int index); +signals: + void NodePositionChanged(const QPointF &pos); + protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -174,6 +178,8 @@ private: QPointF cached_node_pos_; + bool dont_signal_; + }; } diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index 4853c0e99..057a9c01b 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -159,6 +159,7 @@ NodeViewItem* NodeViewScene::AddNode(Node* node) connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeAppearanceChanged); connect(node, &Node::ColorChanged, this, &NodeViewScene::NodeAppearanceChanged); + connect(item, &NodeViewItem::NodePositionChanged, this, &NodeViewScene::NodeItemPositionChanged); return item; } @@ -278,4 +279,10 @@ void NodeViewScene::NodeAppearanceChanged() item_map_.value(static_cast(sender()))->update(); } +void NodeViewScene::NodeItemPositionChanged(const QPointF &pos) +{ + NodeViewItem *item = static_cast(sender()); + emit NodePositionChanged(item, pos); +} + } diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index 272c592ce..267807812 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -106,6 +106,9 @@ public slots: */ void SetEdgesAreCurved(bool curved); +signals: + void NodePositionChanged(NodeViewItem *node, const QPointF &pos); + private: static int DetermineWeight(Node* n); @@ -127,6 +130,8 @@ private slots: */ void NodeAppearanceChanged(); + void NodeItemPositionChanged(const QPointF &pos); + }; }