diff --git a/app/node/node.cpp b/app/node/node.cpp index ffde76468..8f42b9dc2 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -558,6 +558,8 @@ const QPointF &Node::GetPosition() void Node::SetPosition(const QPointF &pos) { position_ = pos; + + emit PositionChanged(position_); } void Node::AddInput(NodeInput *input) diff --git a/app/node/node.h b/app/node/node.h index 16b33c8c1..656713224 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -384,6 +384,11 @@ signals: */ void EdgeRemoved(NodeEdgePtr edge); + /** + * @brief Signal emitted whenever the position is set through SetPosition() + */ + void PositionChanged(const QPointF& pos); + private: /** * @brief Add a parameter to this node diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 4f57c3d2d..6f005a46c 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -45,7 +45,7 @@ NodeView::NodeView(QWidget *parent) : connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot); connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu); - SetFlowDirection(NodeViewCommon::kTopToBottom); + SetFlowDirection(NodeViewCommon::kLeftToRight); } NodeView::~NodeView() diff --git a/app/widget/nodeview/nodeviewcommon.h b/app/widget/nodeview/nodeviewcommon.h index c54ffe89f..cc2b870fe 100644 --- a/app/widget/nodeview/nodeviewcommon.h +++ b/app/widget/nodeview/nodeviewcommon.h @@ -43,6 +43,14 @@ public: return Qt::Horizontal; } } + + static bool DirectionsAreOpposing(FlowDirection a, FlowDirection b) { + return ((a == NodeViewCommon::kLeftToRight && b == NodeViewCommon::kRightToLeft) + || (a == NodeViewCommon::kRightToLeft && b == NodeViewCommon::kLeftToRight) + || (a == NodeViewCommon::kTopToBottom && b == NodeViewCommon::kBottomToTop) + || (a == NodeViewCommon::kBottomToTop && b == NodeViewCommon::kTopToBottom)); + } + }; OLIVE_NAMESPACE_EXIT diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 7afe12687..9c3b122e6 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -68,6 +68,57 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) : setRect(title_bar_rect_); } +QPointF NodeViewItem::GetNodePosition() const +{ + QPointF node_pos; + + qreal adjusted_x = pos().x() / DefaultItemHorizontalPadding(); + qreal adjusted_y = pos().y() / DefaultItemVerticalPadding(); + + switch (flow_dir_) { + case NodeViewCommon::kLeftToRight: + node_pos.setX(adjusted_x); + node_pos.setY(adjusted_y); + break; + case NodeViewCommon::kRightToLeft: + node_pos.setX(-adjusted_x); + node_pos.setY(adjusted_y); + break; + case NodeViewCommon::kTopToBottom: + node_pos.setX(adjusted_y); + node_pos.setY(adjusted_x); + break; + case NodeViewCommon::kBottomToTop: + node_pos.setX(-adjusted_y); + node_pos.setY(adjusted_x); + break; + } + + return node_pos; +} + +void NodeViewItem::SetNodePosition(const QPointF &pos) +{ + switch (flow_dir_) { + case NodeViewCommon::kLeftToRight: + setPos(pos.x() * DefaultItemHorizontalPadding(), + pos.y() * DefaultItemVerticalPadding()); + break; + case NodeViewCommon::kRightToLeft: + setPos(-pos.x() * DefaultItemHorizontalPadding(), + pos.y() * DefaultItemVerticalPadding()); + break; + case NodeViewCommon::kTopToBottom: + setPos(pos.y() * DefaultItemHorizontalPadding(), + pos.x() * DefaultItemVerticalPadding()); + break; + case NodeViewCommon::kBottomToTop: + setPos(pos.y() * DefaultItemHorizontalPadding(), + -pos.x() * DefaultItemVerticalPadding()); + break; + } +} + int NodeViewItem::DefaultTextPadding() { return QFontMetrics(QFont()).height() / 4; @@ -88,6 +139,24 @@ int NodeViewItem::DefaultItemBorder() return QFontMetrics(QFont()).height() / 12; } +qreal NodeViewItem::DefaultItemHorizontalPadding() const +{ + if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) { + return DefaultItemWidth() * 1.5; + } else { + return DefaultItemWidth() * 1.25; + } +} + +qreal NodeViewItem::DefaultItemVerticalPadding() const +{ + if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) { + return DefaultItemHeight() * 1.5; + } else { + return DefaultItemHeight() * 2.0; + } +} + void NodeViewItem::SetNode(Node *n) { node_ = n; @@ -241,8 +310,8 @@ void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) drag_source_ = static_cast(scene())->NodeToUIObject(drag_src_param_->parentNode()); // Get the opposing parameter's rect center using the line's current coordinates - // (we use the current coordinates because a complex formula is used for the line's coords if the opposing - // node is collapsed, therefore it's easier to just retrieve it from line itself) + // (we use the current coordinates because a complex formula is used for the line's coords if + // the opposing node is collapsed, therefore it's easier to just retrieve it from line itself) NodeViewEdge* existing_edge_ui = static_cast(scene())->EdgeToUIObject(edge); QPainterPath existing_edge_line = existing_edge_ui->path(); QPointF edge_start = existing_edge_line.pointAtPercent(0); @@ -422,7 +491,9 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionHasChanged && node_) { - node_->SetPosition(value.toPointF()); + node_->blockSignals(true); + node_->SetPosition(GetNodePosition()); + node_->blockSignals(false); } return QGraphicsItem::itemChange(change, value); diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 28bc9a932..9d1999b28 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -46,6 +46,9 @@ class NodeViewItem : public QGraphicsRectItem public: NodeViewItem(QGraphicsItem* parent = nullptr); + QPointF GetNodePosition() const; + void SetNodePosition(const QPointF& pos); + /** * @brief Set the Node to correspond to this widget */ @@ -85,6 +88,10 @@ public: static int DefaultItemBorder(); + qreal DefaultItemHorizontalPadding() const; + + qreal DefaultItemVerticalPadding() const; + protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index a1604d0c1..bcadfd733 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -37,13 +37,18 @@ void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction) direction_ = direction; { + // Iterate over node items setting direction QHash::const_iterator i; for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) { i.value()->SetFlowDirection(direction_); + + // Update position too + i.value()->SetNodePosition(i.key()->GetPosition()); } } { + // Iterate over edge items setting direction QHash::const_iterator i; for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) { i.value()->SetFlowDirection(direction_); @@ -173,10 +178,14 @@ void NodeViewScene::AddNode(Node* node) } } } + + connect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged); } void NodeViewScene::RemoveNode(Node *node) { + disconnect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged); + delete item_map_.take(node); } @@ -215,59 +224,23 @@ void NodeViewScene::ReorganizeFrom(Node* n) return; } - NodeViewItem* parent_item = NodeToUIObject(n); + QPointF parent_pos = n->GetPosition(); - int item_sz, item_padding, layer_diff, total_top; - - if (GetFlowOrientation() == Qt::Vertical) { - item_sz = NodeViewItem::DefaultItemWidth(); - item_padding = item_sz / 2; - layer_diff = NodeViewItem::DefaultItemHeight() * 2; - total_top = parent_item->x(); - } else { - item_sz = NodeViewItem::DefaultItemHeight(); - item_padding = item_sz; - layer_diff = NodeViewItem::DefaultItemWidth() * 3 / 2; - total_top = parent_item->y(); - } - - int item_sz_with_padding = item_sz + item_padding; - - int total_sz = item_sz_with_padding * immediates.size() - item_padding; - - total_top -= total_sz / 2; - total_top += item_sz / 2; - - int item_layer_pos; - - switch (direction_) { - case NodeViewCommon::kTopToBottom: - item_layer_pos = parent_item->pos().y() - layer_diff; - break; - case NodeViewCommon::kLeftToRight: - item_layer_pos = parent_item->pos().x() - layer_diff; - break; - case NodeViewCommon::kBottomToTop: - item_layer_pos = parent_item->pos().y() + layer_diff; - break; - case NodeViewCommon::kRightToLeft: - item_layer_pos = parent_item->pos().x() + layer_diff; - break; - } + qreal child_x = parent_pos.x() - 1.0; + qreal children_height = immediates.size()-1; + qreal children_y = parent_pos.y() - children_height * 0.5; for (int i=0;isetPos(total_top + item_sz_with_padding * i, - item_layer_pos); - } else { - item->setPos(item_layer_pos, - total_top + item_sz_with_padding * i); - } + immediates.at(i)->SetPosition(QPointF(child_x, + children_y + i)); ReorganizeFrom(immediates.at(i)); } } +void NodeViewScene::NodePositionChanged(const QPointF &pos) +{ + item_map_.value(static_cast(sender()))->SetNodePosition(pos); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index 48d4adba2..ee4040c5f 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -121,6 +121,13 @@ private: NodeViewCommon::FlowDirection direction_; +private slots: + /** + * @brief Receiver for whenever a node position changes + */ + void NodePositionChanged(const QPointF& pos); + + }; OLIVE_NAMESPACE_EXIT