From 603303904627cfd98b79e4aca9d557f1d6791b5e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 10 Nov 2021 21:59:54 -0800 Subject: [PATCH] improved connector UI in node view --- app/node/output/track/track.cpp | 3 +- app/node/output/track/track.h | 15 +- app/node/output/track/tracklist.cpp | 2 + app/widget/nodeview/CMakeLists.txt | 2 + app/widget/nodeview/nodeview.cpp | 5 +- app/widget/nodeview/nodeviewcontext.cpp | 80 +++++++++- app/widget/nodeview/nodeviewcontext.h | 9 ++ app/widget/nodeview/nodeviewedge.cpp | 8 +- app/widget/nodeview/nodeviewitem.cpp | 140 ++++++++++++------ app/widget/nodeview/nodeviewitem.h | 22 ++- app/widget/nodeview/nodeviewitemconnector.cpp | 81 ++++++++++ app/widget/nodeview/nodeviewitemconnector.h | 40 +++++ app/widget/nodeview/nodeviewscene.cpp | 61 ++------ app/widget/nodeview/nodeviewscene.h | 26 ---- app/widget/timelinewidget/tool/import.cpp | 6 +- 15 files changed, 352 insertions(+), 148 deletions(-) create mode 100644 app/widget/nodeview/nodeviewitemconnector.cpp create mode 100644 app/widget/nodeview/nodeviewitemconnector.h diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 41eda30f2..e1cb208d6 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -41,7 +41,8 @@ const QString Track::kMutedInput = QStringLiteral("muted_in"); Track::Track() : track_type_(Track::kNone), index_(-1), - locked_(false) + locked_(false), + sequence_(nullptr) { AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable)); diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index d6179eaf4..2e9b44ab3 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -26,6 +26,8 @@ namespace olive { +class Sequence; + /** * @brief A time traversal Node for sorting through one channel/track of Blocks */ @@ -388,9 +390,18 @@ public: bool IsLocked() const; - int GetArrayIndexFromBlock(Block* block) const; + Sequence *sequence() const + { + return sequence_; + } + + void set_sequence(Sequence *sequence) + { + sequence_ = sequence; + } + static const double kTrackHeightDefault; static const double kTrackHeightMinimum; static const double kTrackHeightInterval; @@ -472,6 +483,8 @@ private: bool locked_; + Sequence *sequence_; + private slots: void BlockLengthChanged(); diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index c9f35e26f..f5d233515 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -83,6 +83,7 @@ void TrackList::TrackConnected(Node *node, int element) connect(track, &Track::TrackLengthChanged, this, &TrackList::UpdateTotalLength); track->set_type(type_); + track->set_sequence(parent()); emit TrackListChanged(); @@ -121,6 +122,7 @@ void TrackList::TrackDisconnected(Node *node, int element) track->SetIndex(-1); track->set_type(Track::kNone); + track->set_sequence(nullptr); disconnect(track, &Track::TrackLengthChanged, this, &TrackList::UpdateTotalLength); diff --git a/app/widget/nodeview/CMakeLists.txt b/app/widget/nodeview/CMakeLists.txt index e7f94c762..12512695f 100644 --- a/app/widget/nodeview/CMakeLists.txt +++ b/app/widget/nodeview/CMakeLists.txt @@ -25,6 +25,8 @@ set(OLIVE_SOURCES widget/nodeview/nodeviewedge.h widget/nodeview/nodeviewitem.cpp widget/nodeview/nodeviewitem.h + widget/nodeview/nodeviewitemconnector.cpp + widget/nodeview/nodeviewitemconnector.h widget/nodeview/nodeviewminimap.cpp widget/nodeview/nodeviewminimap.h widget/nodeview/nodeviewscene.cpp diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index b694992b3..86b1c5711 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -847,7 +847,7 @@ void NodeView::UpdateSelectionCache() void NodeView::ShowContextMenu(const QPoint &pos) { - if (!graph_) { + if (filter_nodes_.isEmpty()) { return; } @@ -1023,7 +1023,6 @@ void NodeView::RemoveNode(Node *node) scene_.RemoveEdge(it->second, it->first); } positions_.remove(scene_.item_map().value(node)); - scene_.RemoveNode(node); } void NodeView::AddEdge(Node *output, const NodeInput &input) @@ -1645,8 +1644,6 @@ NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context) // Get UI item or create if it doesn't exist NodeViewItem *item = scene_.item_map().value(node); if (!item) { - item = scene_.AddNode(node); - for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { if (scene_.item_map().contains(it->second)) { scene_.AddEdge(it->second, it->first); diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp index ad1bdc6ac..0e8262b3e 100644 --- a/app/widget/nodeview/nodeviewcontext.cpp +++ b/app/widget/nodeview/nodeviewcontext.cpp @@ -6,8 +6,11 @@ #include #include +#include "core.h" #include "node/block/block.h" +#include "node/graph.h" #include "node/output/track/track.h" +#include "node/project/sequence/sequence.h" #include "nodeviewitem.h" #include "ui/colorcoding.h" @@ -31,11 +34,12 @@ void NodeViewContext::SetContext(Node *node) if (context_) { if (Block *block = dynamic_cast(node)) { + rational timebase = block->track()->sequence()->GetVideoParams().frame_rate_as_time_base(); lbl_ = QCoreApplication::translate("NodeViewContext", - "%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(), - Track::Reference::TypeToTranslatedString(block->track()->type()), - block->in().toString(), - block->out().toString()); + "%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(), + Track::Reference::TypeToTranslatedString(block->track()->type()), + Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()), + Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay())); } else { lbl_ = node->GetLabelAndName(); } @@ -52,8 +56,38 @@ void NodeViewContext::SetContext(Node *node) void NodeViewContext::AddChild(Node *node) { + if (!context_) { + return; + } + NodeViewItem *item = new NodeViewItem(this); item->SetNode(node); + item->SetNodePosition(context_->parent()->GetNodesForContext(context_).value(node)); + item->SetFlowDirection(flow_dir_); + + if (node == context_) { + item->SetLabelAsOutput(true); + } + + for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) { + foreach (auto child, childItems()) { + if (NodeViewItem *other_item = dynamic_cast(child)) { + if (other_item->GetNode() == it->second.node()) { + AddEdgeInternal(node, it->second, item, other_item); + } + } + } + } + + for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { + foreach (auto child, childItems()) { + if (NodeViewItem *other_item = dynamic_cast(child)) { + if (it->second == other_item->GetNode()) { + AddEdgeInternal(it->second, it->first, other_item, item); + } + } + } + } } qreal GetTextOffset(const QFontMetricsF &fm) @@ -75,12 +109,31 @@ void NodeViewContext::UpdateRect() void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir) { - auto children = childItems(); - foreach (auto child, children) { + flow_dir_ = dir; + + foreach (auto child, childItems()) { if (NodeViewItem *item = dynamic_cast(child)) { item->SetFlowDirection(dir); } } + + foreach (auto child, childItems()) { + if (NodeViewEdge *edge = dynamic_cast(child)) { + edge->SetFlowDirection(dir); + } + } +} + +void NodeViewContext::SetCurvedEdges(bool e) +{ + curved_edges_ = e; + + const QList &children = childItems(); + foreach (auto child, children) { + if (NodeViewEdge *edge = dynamic_cast(child)) { + edge->SetCurved(e); + } + } } void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -97,7 +150,7 @@ void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *o int rounded = painter->fontMetrics().height(); painter->drawRoundedRect(rect(), rounded, rounded); - painter->setPen(context_ ? ColorCoding::GetUISelectorColor(context_->color()) : Qt::white); + painter->setPen(widget->palette().text().color()); int offset = GetTextOffset(painter->fontMetrics()); @@ -111,4 +164,17 @@ QVariant NodeViewContext::itemChange(GraphicsItemChange change, const QVariant & return super::itemChange(change, value); } +NodeViewEdge* NodeViewContext::AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to) +{ + NodeViewEdge* edge_ui = new NodeViewEdge(output, input, from, to, this); + + edge_ui->SetFlowDirection(flow_dir_); + edge_ui->SetCurved(curved_edges_); + + from->AddEdge(edge_ui); + to->AddEdge(edge_ui); + + return edge_ui; +} + } diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h index 4e1a8a866..a5141e32b 100644 --- a/app/widget/nodeview/nodeviewcontext.h +++ b/app/widget/nodeview/nodeviewcontext.h @@ -6,6 +6,7 @@ #include "node/node.h" #include "nodeviewcommon.h" +#include "nodeviewedge.h" namespace olive { @@ -22,16 +23,24 @@ public: void SetFlowDirection(NodeViewCommon::FlowDirection dir); + void SetCurvedEdges(bool e); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; protected: virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; private: + NodeViewEdge *AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to); + Node *context_; QString lbl_; + NodeViewCommon::FlowDirection flow_dir_; + + bool curved_edges_; + }; } diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index 42dd19e06..5498fbefb 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -128,9 +128,11 @@ void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->drawPath(path()); // Draw arrow - painter->setPen(Qt::NoPen); - painter->setBrush(edge_color); - painter->drawPolygon(arrow_); + if (!connected_) { + painter->setPen(Qt::NoPen); + painter->setBrush(edge_color); + painter->drawPolygon(arrow_); + } } void NodeViewEdge::Init() diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index fa362af72..2eb766863 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -46,7 +46,8 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) : hide_titlebar_(false), highlighted_index_(-1), flow_dir_(NodeViewCommon::kLeftToRight), - prevent_removing_(false) + prevent_removing_(false), + label_as_output_(false) { // Set flags for this widget setFlag(QGraphicsItem::ItemIsMovable); @@ -66,7 +67,8 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) : title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height); setRect(title_bar_rect_); - output_triangle_.resize(3); + input_connector_ = new NodeViewItemConnector(this); + output_connector_ = new NodeViewItemConnector(this); } QPointF NodeViewItem::GetNodePosition() const @@ -208,6 +210,11 @@ int NodeViewItem::GetIndexAt(QPointF pt) const void NodeViewItem::SetNode(Node *n) { + if (node_) { + disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged); + disconnect(n, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged); + } + node_ = n; node_inputs_.clear(); @@ -220,6 +227,11 @@ void NodeViewItem::SetNode(Node *n) node_inputs_.append(input); } } + + input_connector_->setVisible(!node_inputs_.isEmpty()); + + connect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged); + connect(n, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged); } update(); @@ -234,6 +246,7 @@ void NodeViewItem::SetExpanded(bool e, bool hide_titlebar) expanded_ = e; hide_titlebar_ = hide_titlebar; + input_connector_->setVisible(!expanded_); if (expanded_ && !node_inputs_.isEmpty()) { // Create new rect @@ -252,7 +265,11 @@ void NodeViewItem::SetExpanded(bool e, bool hide_titlebar) update(); + UpdateConnectorPositions(); + ReadjustAllEdges(); + + UpdateContextRect(); } void NodeViewItem::ToggleExpanded() @@ -298,8 +315,14 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->setPen(app_pal.color(QPalette::Text)); - QString node_label = node_->GetLabel(); - QString node_shortname = node_->ShortName(); + QString node_label, node_shortname; + + if (label_as_output_) { + node_shortname = QCoreApplication::translate("NodeViewItem", "Output"); + } else { + node_label = node_->GetLabel(); + node_shortname = node_->ShortName(); + } int icon_size = painter->fontMetrics().height()/2; @@ -335,41 +358,6 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->setBrush(Qt::NoBrush); painter->drawRect(rect()); - - // Draw output triangle - painter->setPen(Qt::NoPen); - painter->setBrush(app_pal.color(QPalette::Text)); - int triangle_sz = title_bar_rect_.height() / 2; - int triangle_sz_half = triangle_sz / 2; - - switch (flow_dir_) { - case NodeViewCommon::kLeftToRight: - // Triangle pointing right - output_triangle_[0] = QPointF(rect().right(), rect().center().y() - triangle_sz_half); - output_triangle_[1] = QPointF(rect().right() + triangle_sz_half, rect().center().y()); - output_triangle_[2] = QPointF(rect().right(), rect().center().y() + triangle_sz_half); - break; - case NodeViewCommon::kTopToBottom: - // Triangle pointing down - output_triangle_[0] = QPointF(rect().center().x() - triangle_sz_half, rect().bottom()); - output_triangle_[1] = QPointF(rect().center().x(), rect().bottom() + triangle_sz_half); - output_triangle_[2] = QPointF(rect().center().x() + triangle_sz_half, rect().bottom()); - break; - case NodeViewCommon::kBottomToTop: - // Triangle pointing up - output_triangle_[0] = QPointF(rect().center().x() - triangle_sz_half, rect().top()); - output_triangle_[1] = QPointF(rect().center().x(), rect().top() - triangle_sz_half); - output_triangle_[2] = QPointF(rect().center().x() + triangle_sz_half, rect().top()); - break; - case NodeViewCommon::kRightToLeft: - // Triangle pointing left - output_triangle_[0] = QPointF(rect().left(), rect().center().y() - triangle_sz_half); - output_triangle_[1] = QPointF(rect().left() - triangle_sz_half, rect().center().y()); - output_triangle_[2] = QPointF(rect().left(), rect().center().y() + triangle_sz_half); - break; - } - - painter->drawPolygon(output_triangle_); } void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) @@ -407,9 +395,7 @@ QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons if (change == ItemPositionHasChanged && node_) { ReadjustAllEdges(); - if (NodeViewContext *ctx = dynamic_cast(parentItem())) { - ctx->UpdateRect(); - } + UpdateContextRect(); } return QGraphicsItem::itemChange(change, value); @@ -422,6 +408,13 @@ void NodeViewItem::ReadjustAllEdges() } } +void NodeViewItem::UpdateContextRect() +{ + if (NodeViewContext *ctx = dynamic_cast(parentItem())) { + ctx->UpdateRect(); + } +} + void NodeViewItem::DrawNodeTitle(QPainter* painter, QString text, const QRectF& rect, Qt::Alignment vertical_align, int icon_size, bool draw_arrow) { QFontMetrics fm = painter->fontMetrics(); @@ -487,6 +480,13 @@ void NodeViewItem::SetHighlightedIndex(int index) update(); } +void NodeViewItem::SetLabelAsOutput(bool e) +{ + label_as_output_ = e; + output_connector_->setVisible(!e); + update(); +} + QRectF NodeViewItem::GetInputRect(int index) const { QRectF r = title_bar_rect_; @@ -504,28 +504,45 @@ QRectF NodeViewItem::GetInputRect(int index) const QPointF NodeViewItem::GetInputPoint(const QString &input, int element, const QPointF& source_pos) const { - return pos() + GetInputPointInternal(node_inputs_.indexOf(input), source_pos); + if (expanded_) { + return pos() + GetInputPointInternal(node_inputs_.indexOf(input), source_pos); + } else { + return pos() + input_connector_->pos(); + } } QPointF NodeViewItem::GetOutputPoint() const { + QPointF p = pos() + output_connector_->pos(); + QRectF r = output_connector_->boundingRect(); + switch (flow_dir_) { case NodeViewCommon::kLeftToRight: default: - return pos() + QPointF(rect().right(), rect().center().y()); + p.setX(p.x() + r.width()); + break; case NodeViewCommon::kRightToLeft: - return pos() + QPointF(rect().left(), rect().center().y()); + p.setX(p.x() - r.width()); + break; case NodeViewCommon::kTopToBottom: - return pos() + QPointF(rect().center().x(), rect().bottom()); + p.setY(p.y() + r.height()); + break; case NodeViewCommon::kBottomToTop: - return pos() + QPointF(rect().center().x(), rect().top()); + p.setY(p.y() - r.height()); + break; } + + return p; } void NodeViewItem::SetFlowDirection(NodeViewCommon::FlowDirection dir) { flow_dir_ = dir; + input_connector_->SetFlowDirection(dir); + output_connector_->SetFlowDirection(dir); + + UpdateConnectorPositions(); UpdateNodePosition(); } @@ -556,4 +573,33 @@ void NodeViewItem::UpdateNodePosition() setPos(NodeToScreenPoint(cached_node_pos_, flow_dir_)); } +void NodeViewItem::UpdateConnectorPositions() +{ + QRectF output_rect = output_connector_->boundingRect(); + + switch (flow_dir_) { + case NodeViewCommon::kLeftToRight: + input_connector_->setPos(rect().left() - output_rect.width(), rect().center().y()); + output_connector_->setPos(rect().right(), rect().center().y()); + break; + case NodeViewCommon::kRightToLeft: + input_connector_->setPos(rect().right() + output_rect.width(), rect().center().y()); + output_connector_->setPos(rect().left(), rect().center().y()); + break; + case NodeViewCommon::kTopToBottom: + input_connector_->setPos(rect().center().x(), rect().top() - output_rect.height()); + output_connector_->setPos(rect().center().x(), rect().bottom()); + break; + case NodeViewCommon::kBottomToTop: + input_connector_->setPos(rect().center().x(), rect().bottom() + output_rect.height()); + output_connector_->setPos(rect().center().x(), rect().top()); + break; + } +} + +void NodeViewItem::NodeAppearanceChanged() +{ + update(); +} + } diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 3c611d481..bd2cd7ac1 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -28,6 +28,7 @@ #include "node/node.h" #include "nodeviewcommon.h" +#include "nodeviewitemconnector.h" namespace olive { @@ -40,8 +41,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); @@ -125,11 +127,13 @@ public: return prevent_removing_; } - const QPolygonF &GetOutputTriangle() const + QPolygonF GetOutputTriangle() const { - return output_triangle_; + return output_connector_->polygon(); } + void SetLabelAsOutput(bool e); + protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -143,6 +147,8 @@ protected: private: void ReadjustAllEdges(); + void UpdateContextRect(); + void DrawNodeTitle(QPainter *painter, QString text, const QRectF &rect, Qt::Alignment vertical_align, int icon_size, bool draw_arrow); /** @@ -160,6 +166,8 @@ private: */ void UpdateNodePosition(); + void UpdateConnectorPositions(); + /** * @brief Reference to attached Node */ @@ -195,7 +203,13 @@ private: bool prevent_removing_; - QPolygonF output_triangle_; + NodeViewItemConnector *input_connector_; + NodeViewItemConnector *output_connector_; + + bool label_as_output_; + +private slots: + void NodeAppearanceChanged(); }; diff --git a/app/widget/nodeview/nodeviewitemconnector.cpp b/app/widget/nodeview/nodeviewitemconnector.cpp new file mode 100644 index 000000000..650c33ccf --- /dev/null +++ b/app/widget/nodeview/nodeviewitemconnector.cpp @@ -0,0 +1,81 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "nodeviewitemconnector.h" + +#include +#include +#include +#include + +#include "nodeviewitem.h" + +namespace olive { + +NodeViewItemConnector::NodeViewItemConnector(QGraphicsItem *parent) : + QGraphicsPolygonItem(parent) +{ + QColor c = qApp->palette().text().color(); + setPen(QPen(c, NodeViewItem::DefaultItemBorder())); + setBrush(c); +} + +void NodeViewItemConnector::SetFlowDirection(NodeViewCommon::FlowDirection dir) +{ + QFont f; + QFontMetricsF fm(f); + + int triangle_sz = fm.height()/2; + int triangle_sz_half = triangle_sz / 2; + + QPolygonF p; + p.resize(3); + + switch (dir) { + case NodeViewCommon::kLeftToRight: + // Triangle pointing right + p[0] = QPointF(0, -triangle_sz_half); + p[1] = QPointF(triangle_sz_half, 0); + p[2] = QPointF(0, triangle_sz_half); + break; + case NodeViewCommon::kTopToBottom: + // Triangle pointing down + p[0] = QPointF(-triangle_sz_half, 0); + p[1] = QPointF(0, triangle_sz_half); + p[2] = QPointF(triangle_sz_half, 0); + break; + case NodeViewCommon::kBottomToTop: + // Triangle pointing up + p[0] = QPointF(-triangle_sz_half, 0); + p[1] = QPointF(0, -triangle_sz_half); + p[2] = QPointF(triangle_sz_half, 0); + break; + case NodeViewCommon::kRightToLeft: + // Triangle pointing left + p[0] = QPointF(0, -triangle_sz_half); + p[1] = QPointF(-triangle_sz_half, 0); + p[2] = QPointF(0, triangle_sz_half); + break; + } + + setPolygon(p); +} + +} diff --git a/app/widget/nodeview/nodeviewitemconnector.h b/app/widget/nodeview/nodeviewitemconnector.h new file mode 100644 index 000000000..6dfc7d9d3 --- /dev/null +++ b/app/widget/nodeview/nodeviewitemconnector.h @@ -0,0 +1,40 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef NODEVIEWITEMCONNECTOR_H +#define NODEVIEWITEMCONNECTOR_H + +#include + +#include "nodeviewcommon.h" + +namespace olive { + +class NodeViewItemConnector : public QGraphicsPolygonItem +{ +public: + NodeViewItemConnector(QGraphicsItem *parent = nullptr); + + void SetFlowDirection(NodeViewCommon::FlowDirection dir); +}; + +} + +#endif // NODEVIEWITEMCONNECTOR_H diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index 56de3d250..feb2598b3 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -38,19 +38,13 @@ 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_); - } + foreach (NodeViewContext *ctx, context_map_) { + ctx->SetFlowDirection(direction_); } - { - // Iterate over edge items setting direction - foreach (NodeViewEdge* edge, edges_) { - edge->SetFlowDirection(direction_); - } + // Iterate over edge items setting direction + foreach (NodeViewEdge* edge, edges_) { + edge->SetFlowDirection(direction_); } } @@ -66,7 +60,6 @@ void NodeViewScene::clear() selectedItems(); for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) { - DisconnectNode(it.key()); delete it.value(); } item_map_.clear(); @@ -150,28 +143,6 @@ QVector NodeViewScene::GetSelectedEdges() const return edges; } -NodeViewItem* NodeViewScene::AddNode(Node* node) -{ - NodeViewItem* item = new NodeViewItem(); - - item->SetFlowDirection(direction_); - item->SetNode(node); - - addItem(item); - item_map_.insert(node, item); - - ConnectNode(node); - - return item; -} - -void NodeViewScene::RemoveNode(Node *node) -{ - DisconnectNode(node); - - delete item_map_.take(node); -} - NodeViewEdge* NodeViewScene::AddEdge(Node *output, const NodeInput &input) { NodeViewEdge *edge = EdgeToUIObject(output, input); @@ -202,6 +173,8 @@ NodeViewContext *NodeViewScene::AddContext(Node *node) context_item = new NodeViewContext(); context_item->SetContext(node); context_item->setPos(0, 0); + context_item->SetFlowDirection(GetFlowDirection()); + context_item->SetCurvedEdges(GetEdgesAreCurved()); addItem(context_item); const NodeGraph::PositionMap &map = node->parent()->GetNodesForContext(node); @@ -209,6 +182,8 @@ NodeViewContext *NodeViewScene::AddContext(Node *node) context_item->AddChild(it.key()); } context_item->UpdateRect(); + + context_map_.insert(node, context_item); } return context_item; @@ -250,18 +225,6 @@ NodeViewEdge* NodeViewScene::AddEdgeInternal(Node *output, const NodeInput& inpu return edge_ui; } -void NodeViewScene::ConnectNode(Node *n) -{ - connect(n, &Node::LabelChanged, this, &NodeViewScene::NodeAppearanceChanged); - connect(n, &Node::ColorChanged, this, &NodeViewScene::NodeAppearanceChanged); -} - -void NodeViewScene::DisconnectNode(Node *n) -{ - disconnect(n, &Node::ColorChanged, this, &NodeViewScene::NodeAppearanceChanged); - disconnect(n, &Node::LabelChanged, this, &NodeViewScene::NodeAppearanceChanged); -} - Qt::Orientation NodeViewScene::GetFlowOrientation() const { return NodeViewCommon::GetFlowOrientation(direction_); @@ -283,10 +246,4 @@ void NodeViewScene::SetEdgesAreCurved(bool curved) } } -void NodeViewScene::NodeAppearanceChanged() -{ - // Force item to update - item_map_.value(static_cast(sender()))->update(); -} - } diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index 4f6357dee..f37ebbdcd 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -81,22 +81,6 @@ public: } public slots: - /** - * @brief Slot when a Node is added to a graph (SetGraph() connects this) - * - * This should NEVER be called directly, only connected to a NodeGraph. To add a Node to the NodeGraph - * use NodeGraph::AddNode(). - */ - NodeViewItem *AddNode(Node* node); - - /** - * @brief Slot when a Node is removed from a graph (SetGraph() connects this) - * - * This should NEVER be called directly, only connected to a NodeGraph. To remove a Node from the NodeGraph - * use NodeGraph::RemoveNode(). - */ - void RemoveNode(Node* node); - NodeViewEdge *AddEdge(Node *output, const NodeInput& input); void RemoveEdge(Node *output, const NodeInput& input); @@ -113,10 +97,6 @@ private: NodeViewEdge* AddEdgeInternal(Node *output, const NodeInput &input, NodeViewItem* from, NodeViewItem* to); - void ConnectNode(Node *n); - - void DisconnectNode(Node *n); - QHash context_map_; QHash item_map_; @@ -129,12 +109,6 @@ private: bool curved_edges_; -private slots: - /** - * @brief Receiver for when a node's label has changed - */ - void NodeAppearanceChanged(); - }; } diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 5f379679f..9ad1a6a74 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -397,7 +397,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false)); // Position footage in its context - command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(-2, 0), false)); + command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(-3, 0), false)); switch (Track::Reference::TypeFromString(footage_stream.output)) { case Track::kVideo: @@ -409,7 +409,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(transform, TransformDistortNode::kTextureInput))); command->add_child(new NodeEdgeAddCommand(transform, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(-1, 0), false)); + command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(-2, 0), false)); break; } case Track::kAudio: @@ -421,7 +421,7 @@ void ImportTool::DropGhosts(bool insert) command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(volume_node, VolumeNode::kSamplesInput))); command->add_child(new NodeEdgeAddCommand(volume_node, NodeInput(clip, ClipBlock::kBufferIn))); - command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(-1, 0), false)); + command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(-2, 0), false)); break; } default: