nodeview: update positions correctly
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "nodeview.h"
|
#include "nodeview.h"
|
||||||
|
|
||||||
|
#include <cfloat>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
@@ -56,6 +57,7 @@ NodeView::NodeView(QWidget *parent) :
|
|||||||
setViewportUpdateMode(FullViewportUpdate);
|
setViewportUpdateMode(FullViewportUpdate);
|
||||||
|
|
||||||
connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu);
|
connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu);
|
||||||
|
connect(&scene_, &NodeViewScene::NodePositionChanged, this, &NodeView::NodePositionChanged);
|
||||||
|
|
||||||
ConnectSelectionChangedSignal();
|
ConnectSelectionChangedSignal();
|
||||||
|
|
||||||
@@ -70,106 +72,120 @@ NodeView::~NodeView()
|
|||||||
|
|
||||||
void NodeView::SetGraph(NodeGraph *graph, const QVector<void*> &nodes)
|
void NodeView::SetGraph(NodeGraph *graph, const QVector<void*> &nodes)
|
||||||
{
|
{
|
||||||
// Handle potentially changing graph
|
bool graph_changed = graph_ != graph;
|
||||||
if (graph_ != graph) {
|
bool context_changed = filter_nodes_ != nodes;
|
||||||
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);
|
|
||||||
|
|
||||||
if (filter_mode_ == kFilterShowAll) {
|
if (graph_changed || context_changed) {
|
||||||
// Switching graphs, close all nodes
|
// Clear nodes if necessary
|
||||||
DeselectAll();
|
bool refresh_required = (graph_changed && filter_mode_ == kFilterShowAll)
|
||||||
scene_.clear();
|
|| (context_changed && filter_mode_ == kFilterShowSelective);
|
||||||
}
|
bool nodes_visible = (graph && filter_mode_ == kFilterShowAll)
|
||||||
}
|
|| (!nodes.isEmpty() && filter_mode_ == kFilterShowSelective);
|
||||||
|
|
||||||
graph_ = graph;
|
if (refresh_required) {
|
||||||
|
|
||||||
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) {
|
|
||||||
DeselectAll();
|
DeselectAll();
|
||||||
|
positions_.clear();
|
||||||
scene_.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<NodeViewItem*, QVector<QPointF> > averaged_positions;
|
QMap<NodeViewItem*, QVector<QPointF> > averaged_positions;
|
||||||
|
|
||||||
QPointF origin(0, 0);
|
QPointF origin(0, 0);
|
||||||
|
|
||||||
foreach (void *n, filter_nodes_) {
|
if (filter_mode_ == kFilterShowAll) {
|
||||||
const NodeGraph::PositionMap &map = graph_->GetNodesForRelative(n);
|
// 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++) {
|
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
||||||
NodeViewItem *item = scene_.item_map().value(it.key());
|
// Determine position
|
||||||
|
NodeViewItem *item = scene_.item_map().value(it.key());
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
QVector<QPointF> &averages = averaged_positions[item];
|
QVector<QPointF> &averages = averaged_positions[item];
|
||||||
if (averages.isEmpty()) {
|
if (averages.isEmpty()) {
|
||||||
averages.append(item->GetNodePosition());
|
averages.append(item->GetNodePosition());
|
||||||
|
}
|
||||||
|
averages.append(origin + it.value());
|
||||||
|
} else {
|
||||||
|
item = scene_.AddNode(it.key());
|
||||||
}
|
}
|
||||||
averages.append(origin + it.value());
|
|
||||||
} else {
|
const QPointF &pos = it.value();
|
||||||
item = scene_.AddNode(it.key());
|
top = qMin(top, pos.y());
|
||||||
|
bottom = qMax(bottom, pos.y());
|
||||||
|
|
||||||
|
item->SetNodePosition(origin + pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPointF &pos = it.value();
|
origin.setY(origin.y() + 1 + (bottom - top));
|
||||||
top = qMin(top, pos.y());
|
|
||||||
bottom = qMax(bottom, pos.y());
|
|
||||||
|
|
||||||
item->SetNodePosition(origin + pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
origin.setY(origin.y() + 1 + (bottom - top));
|
for (auto it=averaged_positions.cbegin(); it!=averaged_positions.cend(); it++) {
|
||||||
}
|
const QVector<QPointF> &positions = it.value();
|
||||||
|
double x = DBL_MAX;
|
||||||
|
double y = 0.0;
|
||||||
|
|
||||||
for (auto it=scene_.item_map().cbegin(); it!=scene_.item_map().cend(); it++) {
|
// Min the X value and average the Y values
|
||||||
Node *node = it.key();
|
foreach (const QPointF &pos, positions) {
|
||||||
for (auto jt=node->input_connections().cbegin(); jt!=node->input_connections().cend(); jt++) {
|
x = qMin(x, pos.x());
|
||||||
const NodeOutput &output = jt->second;
|
y += pos.y();
|
||||||
if (scene_.item_map().contains(output.node())) {
|
|
||||||
// Create edge since both input and output exist
|
|
||||||
scene_.AddEdge(output, jt->first);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto it=averaged_positions.cbegin(); it!=averaged_positions.cend(); it++) {
|
y /= positions.size();
|
||||||
const QVector<QPointF> &positions = it.value();
|
|
||||||
QPointF p;
|
it.key()->SetNodePosition(QPointF(x, y));
|
||||||
foreach (const QPointF &pos, positions) {
|
}
|
||||||
p += pos;
|
|
||||||
|
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)
|
void NodeView::AddNodePosition(Node *node, void *relative, const QPointF &pos)
|
||||||
{
|
{
|
||||||
if (filter_mode_ == kFilterShowSelective) {
|
/*if (filter_mode_ == kFilterShowSelective) {
|
||||||
if (filter_nodes_.contains(relative)) {
|
if (filter_nodes_.contains(relative)) {
|
||||||
NodeViewItem *item = scene_.item_map().value(node);
|
NodeViewItem *item = scene_.item_map().value(node);
|
||||||
|
|
||||||
@@ -1003,7 +1019,7 @@ void NodeView::AddNodePosition(Node *node, void *relative, const QPointF &pos)
|
|||||||
|
|
||||||
item->SetNodePosition(pos);
|
item->SetNodePosition(pos);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::RemoveNodePosition(Node *node, void *relative)
|
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<Node *> &nodes)
|
void NodeView::AttachNodesToCursor(const QVector<Node *> &nodes)
|
||||||
{
|
{
|
||||||
QVector<NodeViewItem*> items(nodes.size());
|
QVector<NodeViewItem*> items(nodes.size());
|
||||||
|
|||||||
@@ -155,6 +155,13 @@ private:
|
|||||||
kFilterShowSelective
|
kFilterShowSelective
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Position {
|
||||||
|
Node *node;
|
||||||
|
QPointF original_item_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
QMap<NodeViewItem *, Position> positions_;
|
||||||
|
|
||||||
FilterMode filter_mode_;
|
FilterMode filter_mode_;
|
||||||
|
|
||||||
QVector<void*> filter_nodes_;
|
QVector<void*> filter_nodes_;
|
||||||
@@ -209,6 +216,8 @@ private slots:
|
|||||||
void AddNodePosition(Node *node, void *relative, const QPointF &pos);
|
void AddNodePosition(Node *node, void *relative, const QPointF &pos);
|
||||||
void RemoveNodePosition(Node *node, void *relative);
|
void RemoveNodePosition(Node *node, void *relative);
|
||||||
|
|
||||||
|
void NodePositionChanged(NodeViewItem *item, const QPointF &pos);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
|||||||
expanded_(false),
|
expanded_(false),
|
||||||
hide_titlebar_(false),
|
hide_titlebar_(false),
|
||||||
highlighted_index_(-1),
|
highlighted_index_(-1),
|
||||||
flow_dir_(NodeViewCommon::kLeftToRight)
|
flow_dir_(NodeViewCommon::kLeftToRight),
|
||||||
|
dont_signal_(false)
|
||||||
{
|
{
|
||||||
// Set flags for this widget
|
// Set flags for this widget
|
||||||
setFlag(QGraphicsItem::ItemIsMovable);
|
setFlag(QGraphicsItem::ItemIsMovable);
|
||||||
@@ -336,6 +337,10 @@ QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons
|
|||||||
{
|
{
|
||||||
if (change == ItemPositionHasChanged && node_) {
|
if (change == ItemPositionHasChanged && node_) {
|
||||||
ReadjustAllEdges();
|
ReadjustAllEdges();
|
||||||
|
|
||||||
|
if (!dont_signal_) {
|
||||||
|
emit NodePositionChanged(GetNodePosition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QGraphicsItem::itemChange(change, value);
|
return QGraphicsItem::itemChange(change, value);
|
||||||
@@ -479,6 +484,8 @@ QPointF NodeViewItem::GetInputPointInternal(int index, const QPointF& source_pos
|
|||||||
|
|
||||||
void NodeViewItem::UpdateNodePosition()
|
void NodeViewItem::UpdateNodePosition()
|
||||||
{
|
{
|
||||||
|
dont_signal_ = true;
|
||||||
|
|
||||||
const QPointF &pos = cached_node_pos_;
|
const QPointF &pos = cached_node_pos_;
|
||||||
|
|
||||||
switch (flow_dir_) {
|
switch (flow_dir_) {
|
||||||
@@ -499,6 +506,8 @@ void NodeViewItem::UpdateNodePosition()
|
|||||||
-pos.x() * DefaultItemVerticalPadding());
|
-pos.x() * DefaultItemVerticalPadding());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dont_signal_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ class NodeViewEdge;
|
|||||||
*
|
*
|
||||||
* To retrieve the NodeViewItem for a certain Node, use NodeView::NodeToUIObject().
|
* To retrieve the NodeViewItem for a certain Node, use NodeView::NodeToUIObject().
|
||||||
*/
|
*/
|
||||||
class NodeViewItem : public QGraphicsRectItem
|
class NodeViewItem : public QObject, public QGraphicsRectItem
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NodeViewItem(QGraphicsItem* parent = nullptr);
|
NodeViewItem(QGraphicsItem* parent = nullptr);
|
||||||
|
|
||||||
@@ -111,6 +112,9 @@ public:
|
|||||||
|
|
||||||
void SetHighlightedIndex(int index);
|
void SetHighlightedIndex(int index);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void NodePositionChanged(const QPointF &pos);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||||
|
|
||||||
@@ -174,6 +178,8 @@ private:
|
|||||||
|
|
||||||
QPointF cached_node_pos_;
|
QPointF cached_node_pos_;
|
||||||
|
|
||||||
|
bool dont_signal_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ NodeViewItem* NodeViewScene::AddNode(Node* node)
|
|||||||
|
|
||||||
connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeAppearanceChanged);
|
connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeAppearanceChanged);
|
||||||
connect(node, &Node::ColorChanged, this, &NodeViewScene::NodeAppearanceChanged);
|
connect(node, &Node::ColorChanged, this, &NodeViewScene::NodeAppearanceChanged);
|
||||||
|
connect(item, &NodeViewItem::NodePositionChanged, this, &NodeViewScene::NodeItemPositionChanged);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -278,4 +279,10 @@ void NodeViewScene::NodeAppearanceChanged()
|
|||||||
item_map_.value(static_cast<Node*>(sender()))->update();
|
item_map_.value(static_cast<Node*>(sender()))->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeViewScene::NodeItemPositionChanged(const QPointF &pos)
|
||||||
|
{
|
||||||
|
NodeViewItem *item = static_cast<NodeViewItem *>(sender());
|
||||||
|
emit NodePositionChanged(item, pos);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ public slots:
|
|||||||
*/
|
*/
|
||||||
void SetEdgesAreCurved(bool curved);
|
void SetEdgesAreCurved(bool curved);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void NodePositionChanged(NodeViewItem *node, const QPointF &pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int DetermineWeight(Node* n);
|
static int DetermineWeight(Node* n);
|
||||||
|
|
||||||
@@ -127,6 +130,8 @@ private slots:
|
|||||||
*/
|
*/
|
||||||
void NodeAppearanceChanged();
|
void NodeAppearanceChanged();
|
||||||
|
|
||||||
|
void NodeItemPositionChanged(const QPointF &pos);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user