From ce889f68d5a5cdbe8e27771efe48a0e6fae01dad Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 16 Feb 2020 12:40:12 +1100 Subject: [PATCH] nodeview: allow users to place a node on an edge to automatically connect it between the two nodes UI convenience. Edge highlights when the cursor is in range to perform this action. --- app/widget/nodeview/nodeview.cpp | 72 +++++++++++++++++++++++++++- app/widget/nodeview/nodeview.h | 3 ++ app/widget/nodeview/nodeviewedge.cpp | 25 +++++++--- app/widget/nodeview/nodeviewedge.h | 10 ++++ app/widget/nodeview/nodeviewundo.cpp | 8 ++++ app/widget/nodeview/nodeviewundo.h | 1 + 6 files changed, 111 insertions(+), 8 deletions(-) diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index f3539b9b6..a2897d8dc 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -29,7 +29,8 @@ NodeView::NodeView(QWidget *parent) : QGraphicsView(parent), graph_(nullptr), - attached_item_(nullptr) + attached_item_(nullptr), + drop_edge_(nullptr) { setScene(&scene_); setDragMode(RubberBandDrag); @@ -231,7 +232,25 @@ void NodeView::keyPressEvent(QKeyEvent *event) void NodeView::mousePressEvent(QMouseEvent *event) { if (attached_item_) { + Node* dropping_node = attached_item_->node(); + DetachItemFromCursor(); + + if (drop_edge_) { + NodeEdgePtr old_edge = drop_edge_->edge(); + + // We have everything we need to place the node in between + QUndoCommand* command = new QUndoCommand(); + + // Remove old edge + new NodeEdgeRemoveCommand(old_edge, command); + + // Place new edges + new NodeEdgeAddCommand(old_edge->output(), drop_compatible_input_, command); + new NodeEdgeAddCommand(dropping_node->output(), old_edge->input(), command); + + Core::instance()->undo_stack()->push(command); + } } QGraphicsView::mousePressEvent(event); @@ -243,6 +262,57 @@ void NodeView::mouseMoveEvent(QMouseEvent *event) if (attached_item_) { attached_item_->setPos(mapToScene(event->pos())); + + // See if the user clicked on an edge + QRect edge_detect_rect(event->pos(), event->pos()); + + // FIXME: Hardcoded numbers + edge_detect_rect.adjust(-20, -20, 20, 20); + + QList items = this->items(edge_detect_rect); + + NodeViewEdge* new_drop_edge = nullptr; + + foreach (QGraphicsItem* item, items) { + NodeViewEdge* edge = dynamic_cast(item); + + if (edge) { + // Try to place this node inside this edge + + // See if the node we're dropping has an input of a compatible data type + NodeInput* edges_input = edge->edge()->input(); + NodeParam::DataType input_type = edges_input->data_type(); + + NodeInput* compatible_input = nullptr; + + foreach (NodeParam* drop_node_param, attached_item_->node()->parameters()) { + if (drop_node_param->type() == NodeParam::kInput + && static_cast(drop_node_param)->data_type() & input_type) { + compatible_input = static_cast(drop_node_param); + break; + } + } + + if (compatible_input) { + new_drop_edge = edge; + drop_compatible_input_ = compatible_input; + + break; + } + } + } + + if (drop_edge_ != new_drop_edge) { + if (drop_edge_) { + drop_edge_->SetHighlighted(false); + } + + drop_edge_ = new_drop_edge; + + if (drop_edge_) { + drop_edge_->SetHighlighted(true); + } + } } } diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index d79b2b4f5..0a0869fa1 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -114,6 +114,9 @@ private: NodeViewItem* attached_item_; + NodeViewEdge* drop_edge_; + NodeInput* drop_compatible_input_; + QGraphicsScene scene_; QTimer reorganize_timer_; diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index b34eec9ed..b89167788 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -30,7 +30,8 @@ NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : QGraphicsLineItem(parent), edge_(nullptr), - connected_(false) + connected_(false), + highlighted_(false) { // Ensures this UI object is drawn behind other objects setZValue(-1); @@ -101,19 +102,29 @@ void NodeViewEdge::Adjust() void NodeViewEdge::SetConnected(bool c) { connected_ = c; + update(); +} + +void NodeViewEdge::SetHighlighted(bool e) +{ + highlighted_ = e; + update(); } void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - QPalette::ColorGroup color_mode; + QPalette::ColorGroup color_group = QPalette::Active; + QPalette::ColorRole color_role = QPalette::Text; - if (connected_) { - color_mode = QPalette::Active; - } else { - color_mode = QPalette::Disabled; + if (highlighted_) { + color_role = QPalette::Highlight; } - setPen(QPen(widget->palette().color(color_mode, QPalette::Text), edge_width_)); + if (!connected_) { + color_group = QPalette::Disabled; + } + + setPen(QPen(widget->palette().color(color_group, color_role), edge_width_)); QGraphicsLineItem::paint(painter, option, widget); } diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h index a17c6209d..0111a8df8 100644 --- a/app/widget/nodeview/nodeviewedge.h +++ b/app/widget/nodeview/nodeviewedge.h @@ -68,6 +68,13 @@ public: */ void SetConnected(bool c); + /** + * @brief Set highlighted state + * + * Changes color of edge. + */ + void SetHighlighted(bool e); + protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -77,6 +84,9 @@ private: int edge_width_; bool connected_; + + bool highlighted_; + }; #endif // NODEEDGEITEM_H diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index ec9c7b7b8..100fee223 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -45,6 +45,14 @@ NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeOutput *output, NodeInput *inpu { } +NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand *parent) : + QUndoCommand(parent), + output_(edge->output()), + input_(edge->input()), + done_(false) +{ +} + void NodeEdgeRemoveCommand::redo() { if (done_) { diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index c6f8ba826..ce111b9a2 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -36,6 +36,7 @@ private: class NodeEdgeRemoveCommand : public QUndoCommand { public: NodeEdgeRemoveCommand(NodeOutput* output, NodeInput* input, QUndoCommand* parent = nullptr); + NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand* parent = nullptr); virtual void redo() override; virtual void undo() override;