From 9c650883c28e9f4e4044e2d15cf3d02649216346 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Wed, 10 Nov 2021 16:33:59 -0800
Subject: [PATCH 01/34] implement context item in node view
---
app/node/CMakeLists.txt | 2 +
app/node/group.cpp | 30 +++++++
app/node/group.h | 43 +++++++++
app/node/output/track/track.h | 45 ++++++++--
app/widget/nodeview/CMakeLists.txt | 2 +
app/widget/nodeview/nodeview.cpp | 43 ++++++++-
app/widget/nodeview/nodeview.h | 5 ++
app/widget/nodeview/nodeviewcontext.cpp | 114 ++++++++++++++++++++++++
app/widget/nodeview/nodeviewcontext.h | 39 ++++++++
app/widget/nodeview/nodeviewitem.cpp | 4 +
app/widget/nodeview/nodeviewscene.cpp | 25 ++++++
app/widget/nodeview/nodeviewscene.h | 6 ++
12 files changed, 347 insertions(+), 11 deletions(-)
create mode 100644 app/node/group.cpp
create mode 100644 app/node/group.h
create mode 100644 app/widget/nodeview/nodeviewcontext.cpp
create mode 100644 app/widget/nodeview/nodeviewcontext.h
diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt
index d10d5746f..6cd34ca5b 100644
--- a/app/node/CMakeLists.txt
+++ b/app/node/CMakeLists.txt
@@ -34,6 +34,8 @@ set(OLIVE_SOURCES
node/globals.h
node/graph.cpp
node/graph.h
+ node/group.cpp
+ node/group.h
node/hashtraverser.cpp
node/hashtraverser.h
node/inputdragger.cpp
diff --git a/app/node/group.cpp b/app/node/group.cpp
new file mode 100644
index 000000000..7b7ab0c87
--- /dev/null
+++ b/app/node/group.cpp
@@ -0,0 +1,30 @@
+/***
+
+ 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 "group.h"
+
+namespace olive {
+
+NodeGroup::NodeGroup()
+{
+
+}
+
+}
diff --git a/app/node/group.h b/app/node/group.h
new file mode 100644
index 000000000..2f15bbb71
--- /dev/null
+++ b/app/node/group.h
@@ -0,0 +1,43 @@
+/***
+
+ 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 NODEGROUP_H
+#define NODEGROUP_H
+
+#include "node.h"
+
+namespace olive {
+
+class NodeGroup : public Node
+{
+ Q_OBJECT
+public:
+ NodeGroup();
+
+ void SetNodes(Node *nodes);
+
+private:
+ QVector nodes_;
+
+};
+
+}
+
+#endif // NODEGROUP_H
diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h
index 97bb1e7b6..d6179eaf4 100644
--- a/app/node/output/track/track.h
+++ b/app/node/output/track/track.h
@@ -168,17 +168,46 @@ public:
QString ToString() const
{
- QString type_string;
-
- if (type_ == Track::kVideo) {
- type_string = QStringLiteral("v");
- } else if (type_ == Track::kAudio) {
- type_string = QStringLiteral("a");
- } else {
+ QString type_string = TypeToString(type_);
+ if (type_string.isEmpty()) {
return QString();
+ } else {
+ return QStringLiteral("%1:%2").arg(type_string, QString::number(index_));
+ }
+ }
+
+ /// For IDs that shouldn't change between localizations
+ static QString TypeToString(Type type)
+ {
+ switch (type) {
+ case kVideo:
+ return QStringLiteral("v");
+ case kAudio:
+ return QStringLiteral("a");
+ case kSubtitle:
+ return QStringLiteral("s");
+ case kCount:
+ break;
}
- return QStringLiteral("%1:%2").arg(type_string, QString::number(index_));
+ return QString();
+ }
+
+ /// For human-facing strings
+ static QString TypeToTranslatedString(Type type)
+ {
+ switch (type) {
+ case kVideo:
+ return tr("V");
+ case kAudio:
+ return tr("A");
+ case kSubtitle:
+ return tr("S");
+ case kCount:
+ break;
+ }
+
+ return QString();
}
static Type TypeFromString(const QString& s)
diff --git a/app/widget/nodeview/CMakeLists.txt b/app/widget/nodeview/CMakeLists.txt
index e73798ae5..e7f94c762 100644
--- a/app/widget/nodeview/CMakeLists.txt
+++ b/app/widget/nodeview/CMakeLists.txt
@@ -19,6 +19,8 @@ set(OLIVE_SOURCES
widget/nodeview/nodeview.cpp
widget/nodeview/nodeview.h
widget/nodeview/nodeviewcommon.h
+ widget/nodeview/nodeviewcontext.cpp
+ widget/nodeview/nodeviewcontext.h
widget/nodeview/nodeviewedge.cpp
widget/nodeview/nodeviewedge.h
widget/nodeview/nodeviewitem.cpp
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index a375ede4f..b694992b3 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -29,6 +29,7 @@
#include "node/audio/volume/volume.h"
#include "node/distort/transform/transformdistortnode.h"
#include "node/factory.h"
+#include "node/group.h"
#include "node/traverser.h"
#include "widget/menu/menushared.h"
#include "widget/timebased/timebasedview.h"
@@ -62,7 +63,7 @@ NodeView::NodeView(QWidget *parent) :
ConnectSelectionChangedSignal();
- SetFlowDirection(NodeViewCommon::kTopToBottom);
+ SetFlowDirection(NodeViewCommon::kLeftToRight);
UpdateSceneBoundingRect();
connect(&scene_, &QGraphicsScene::changed, this, &NodeView::UpdateSceneBoundingRect);
@@ -85,7 +86,23 @@ NodeView::~NodeView()
void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes)
{
- bool graph_changed = graph_ != graph;
+ // Remove contexts that are no longer in the list
+ foreach (Node *n, filter_nodes_) {
+ if (!nodes.contains(n)) {
+ scene_.RemoveContext(n);
+ }
+ }
+
+ // Add contexts that are now in the list
+ foreach (Node *n, nodes) {
+ if (!filter_nodes_.contains(n)) {
+ scene_.AddContext(n);
+ }
+ }
+
+ filter_nodes_ = nodes;
+
+ /*bool graph_changed = graph_ != graph;
bool context_changed = last_set_filter_nodes_ != nodes;
if (graph_changed || context_changed) {
@@ -144,7 +161,7 @@ void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes)
// Center on something
QMetaObject::invokeMethod(this, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
}
- }
+ }*/
}
void NodeView::ClearGraph()
@@ -850,6 +867,15 @@ void NodeView::ShowContextMenu(const QPoint &pos)
Core::instance()->LabelNodes(scene_.GetSelectedNodes());
});
+ // Grouping
+ if (selected.size() == 1 && dynamic_cast(selected.first()->GetNode())) {
+ QAction *ungroup_action = m.addAction(tr("Ungroup"));
+ connect(ungroup_action, &QAction::triggered, this, &NodeView::UngroupNodes);
+ } else {
+ QAction *group_action = m.addAction(tr("Group"));
+ connect(group_action, &QAction::triggered, this, &NodeView::GroupNodes);
+ }
+
// Color menu
MenuShared::instance()->AddColorCodingMenu(&m);
@@ -1603,6 +1629,17 @@ void NodeView::RepositionContexts()
}
}
+void NodeView::GroupNodes()
+{
+ /*NodeGroup *group = new NodeGroup();
+ selected_nodes_*/
+}
+
+void NodeView::UngroupNodes()
+{
+ static_cast(selected_nodes_.first());
+}
+
NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context)
{
// Get UI item or create if it doesn't exist
diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h
index db03afc08..941120361 100644
--- a/app/widget/nodeview/nodeview.h
+++ b/app/widget/nodeview/nodeview.h
@@ -27,6 +27,7 @@
#include "node/graph.h"
#include "node/nodecopypaste.h"
#include "nodeviewedge.h"
+#include "nodeviewcontext.h"
#include "nodeviewminimap.h"
#include "nodeviewscene.h"
#include "widget/handmovableview/handmovableview.h"
@@ -303,6 +304,10 @@ private slots:
void RepositionContexts();
+ void GroupNodes();
+
+ void UngroupNodes();
+
};
}
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
new file mode 100644
index 000000000..ad1bdc6ac
--- /dev/null
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -0,0 +1,114 @@
+#include "nodeviewcontext.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "node/block/block.h"
+#include "node/output/track/track.h"
+#include "nodeviewitem.h"
+#include "ui/colorcoding.h"
+
+namespace olive {
+
+#define super QGraphicsRectItem
+
+NodeViewContext::NodeViewContext(QGraphicsItem *item) :
+ super(item)
+{
+ setFlag(ItemIsMovable);
+ setFlag(ItemIsSelectable);
+
+ // Set default label text
+ SetContext(nullptr);
+}
+
+void NodeViewContext::SetContext(Node *node)
+{
+ context_ = node;
+
+ if (context_) {
+ if (Block *block = dynamic_cast(node)) {
+ lbl_ = QCoreApplication::translate("NodeViewContext",
+ "%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(),
+ Track::Reference::TypeToTranslatedString(block->track()->type()),
+ block->in().toString(),
+ block->out().toString());
+ } else {
+ lbl_ = node->GetLabelAndName();
+ }
+
+ Color c = node->color();
+ setPen(QPen(c.toQColor(), 2));
+
+ c.set_alpha(0.5f);
+ setBrush(c.toQColor());
+ } else {
+ lbl_ = QCoreApplication::translate("NodeViewContext", "(None)");
+ }
+}
+
+void NodeViewContext::AddChild(Node *node)
+{
+ NodeViewItem *item = new NodeViewItem(this);
+ item->SetNode(node);
+}
+
+qreal GetTextOffset(const QFontMetricsF &fm)
+{
+ return fm.height()/2;
+}
+
+void NodeViewContext::UpdateRect()
+{
+ QFont f;
+ QFontMetricsF fm(f);
+ qreal lbl_offset = GetTextOffset(fm);
+
+ QRectF rect = childrenBoundingRect();
+ int pad = NodeViewItem::DefaultItemHeight();
+ rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad);
+ setRect(rect);
+}
+
+void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir)
+{
+ auto children = childItems();
+ foreach (auto child, children) {
+ if (NodeViewItem *item = dynamic_cast(child)) {
+ item->SetFlowDirection(dir);
+ }
+ }
+}
+
+void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ QPen p = pen();
+
+ if (option->state & QStyle::State_Selected) {
+ p.setStyle(Qt::DotLine);
+ }
+
+ painter->setPen(p);
+ painter->setBrush(brush());
+
+ int rounded = painter->fontMetrics().height();
+ painter->drawRoundedRect(rect(), rounded, rounded);
+
+ painter->setPen(context_ ? ColorCoding::GetUISelectorColor(context_->color()) : Qt::white);
+
+ int offset = GetTextOffset(painter->fontMetrics());
+
+ QRectF text_rect = rect();
+ text_rect.adjust(offset, offset, -offset, -offset);
+ painter->drawText(text_rect, lbl_);
+}
+
+QVariant NodeViewContext::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ return super::itemChange(change, value);
+}
+
+}
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
new file mode 100644
index 000000000..4e1a8a866
--- /dev/null
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -0,0 +1,39 @@
+#ifndef NODEVIEWCONTEXT_H
+#define NODEVIEWCONTEXT_H
+
+#include
+#include
+
+#include "node/node.h"
+#include "nodeviewcommon.h"
+
+namespace olive {
+
+class NodeViewContext : public QGraphicsRectItem
+{
+public:
+ NodeViewContext(QGraphicsItem *item = nullptr);
+
+ void SetContext(Node *node);
+
+ void AddChild(Node *node);
+
+ void UpdateRect();
+
+ void SetFlowDirection(NodeViewCommon::FlowDirection dir);
+
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
+
+protected:
+ virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
+
+private:
+ Node *context_;
+
+ QString lbl_;
+
+};
+
+}
+
+#endif // NODEVIEWCONTEXT_H
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 73e2d8019..fa362af72 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -406,6 +406,10 @@ QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons
{
if (change == ItemPositionHasChanged && node_) {
ReadjustAllEdges();
+
+ if (NodeViewContext *ctx = dynamic_cast(parentItem())) {
+ ctx->UpdateRect();
+ }
}
return QGraphicsItem::itemChange(change, value);
diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp
index 878fd52a4..56de3d250 100644
--- a/app/widget/nodeview/nodeviewscene.cpp
+++ b/app/widget/nodeview/nodeviewscene.cpp
@@ -194,6 +194,31 @@ void NodeViewScene::RemoveEdge(Node *output, const NodeInput &input)
}
}
+NodeViewContext *NodeViewScene::AddContext(Node *node)
+{
+ NodeViewContext *context_item = context_map_.value(node);
+
+ if (!context_item) {
+ context_item = new NodeViewContext();
+ context_item->SetContext(node);
+ context_item->setPos(0, 0);
+ addItem(context_item);
+
+ const NodeGraph::PositionMap &map = node->parent()->GetNodesForContext(node);
+ for (auto it=map.cbegin(); it!=map.cend(); it++) {
+ context_item->AddChild(it.key());
+ }
+ context_item->UpdateRect();
+ }
+
+ return context_item;
+}
+
+void NodeViewScene::RemoveContext(Node *node)
+{
+ delete context_map_.take(node);
+}
+
int NodeViewScene::DetermineWeight(Node *n)
{
QVector inputs = n->GetImmediateDependencies();
diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h
index 29cf5bbb7..4f6357dee 100644
--- a/app/widget/nodeview/nodeviewscene.h
+++ b/app/widget/nodeview/nodeviewscene.h
@@ -25,6 +25,7 @@
#include
#include "node/graph.h"
+#include "nodeviewcontext.h"
#include "nodeviewedge.h"
#include "nodeviewitem.h"
@@ -99,6 +100,9 @@ public slots:
NodeViewEdge *AddEdge(Node *output, const NodeInput& input);
void RemoveEdge(Node *output, const NodeInput& input);
+ NodeViewContext *AddContext(Node *node);
+ void RemoveContext(Node *node);
+
/**
* @brief Set whether edges in this scene should be curved or not
*/
@@ -113,6 +117,8 @@ private:
void DisconnectNode(Node *n);
+ QHash context_map_;
+
QHash item_map_;
QVector edges_;
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 02/34] 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:
From 0c92bc3f08110b63265eed8a44285c6634c1478a Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Wed, 10 Nov 2021 22:32:44 -0800
Subject: [PATCH 03/34] fixed some compile issues on non-msvc
---
app/node/output/track/track.h | 2 ++
app/widget/nodeview/nodeview.cpp | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h
index 2e9b44ab3..a7953ff09 100644
--- a/app/node/output/track/track.h
+++ b/app/node/output/track/track.h
@@ -189,6 +189,7 @@ public:
case kSubtitle:
return QStringLiteral("s");
case kCount:
+ case kNone:
break;
}
@@ -206,6 +207,7 @@ public:
case kSubtitle:
return tr("S");
case kCount:
+ case kNone:
break;
}
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index 86b1c5711..818f55095 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -1636,7 +1636,7 @@ void NodeView::GroupNodes()
void NodeView::UngroupNodes()
{
- static_cast(selected_nodes_.first());
+ //static_cast(selected_nodes_.first());
}
NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context)
From 3c6bc80c8f9db19508097cf298ac96cecb11f1d3 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Fri, 12 Nov 2021 11:06:06 -0800
Subject: [PATCH 04/34] further improved new node view
---
app/widget/nodeview/nodeview.cpp | 2 +-
app/widget/nodeview/nodeviewcommon.h | 10 ++
app/widget/nodeview/nodeviewcontext.cpp | 19 +++-
app/widget/nodeview/nodeviewcontext.h | 4 +
app/widget/nodeview/nodeviewedge.cpp | 2 +-
app/widget/nodeview/nodeviewitem.cpp | 121 ++++++++++++++++--------
app/widget/nodeview/nodeviewitem.h | 18 ++--
7 files changed, 124 insertions(+), 52 deletions(-)
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index 818f55095..d5e85fcfb 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -1535,7 +1535,7 @@ void NodeView::PositionNewEdge(const QPoint &pos)
if (highlight_index >= 0) {
create_edge_dst_input_ = create_edge_dst_->GetInputAtIndex(highlight_index);
create_edge_->SetPoints(create_edge_src_->GetOutputPoint(),
- create_edge_dst_->GetInputPoint(create_edge_dst_input_.input(), create_edge_dst_input_.element(), create_edge_src_->pos()),
+ create_edge_dst_->GetInputPoint(create_edge_dst_input_.input(), create_edge_dst_input_.element()),
true);
} else {
create_edge_dst_input_.Reset();
diff --git a/app/widget/nodeview/nodeviewcommon.h b/app/widget/nodeview/nodeviewcommon.h
index 03c5f8dcf..d0541fba4 100644
--- a/app/widget/nodeview/nodeviewcommon.h
+++ b/app/widget/nodeview/nodeviewcommon.h
@@ -44,6 +44,16 @@ public:
}
}
+ static bool IsFlowVertical(FlowDirection dir)
+ {
+ return dir == kTopToBottom || dir == kBottomToTop;
+ }
+
+ static bool IsFlowHorizontal(FlowDirection dir)
+ {
+ return dir == kLeftToRight || dir == kRightToLeft;
+ }
+
static bool DirectionsAreOpposing(FlowDirection a, FlowDirection b) {
return ((a == NodeViewCommon::kLeftToRight && b == NodeViewCommon::kRightToLeft)
|| (a == NodeViewCommon::kRightToLeft && b == NodeViewCommon::kLeftToRight)
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
index 0e8262b3e..db22be143 100644
--- a/app/widget/nodeview/nodeviewcontext.cpp
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
@@ -21,9 +22,6 @@ namespace olive {
NodeViewContext::NodeViewContext(QGraphicsItem *item) :
super(item)
{
- setFlag(ItemIsMovable);
- setFlag(ItemIsSelectable);
-
// Set default label text
SetContext(nullptr);
}
@@ -101,10 +99,13 @@ void NodeViewContext::UpdateRect()
QFontMetricsF fm(f);
qreal lbl_offset = GetTextOffset(fm);
- QRectF rect = childrenBoundingRect();
+ QRectF cbr = childrenBoundingRect();
+ QRectF rect = cbr;
int pad = NodeViewItem::DefaultItemHeight();
rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad);
setRect(rect);
+
+ last_titlebar_height_ = rect.y() + (cbr.y() - rect.y());
}
void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir)
@@ -164,6 +165,16 @@ QVariant NodeViewContext::itemChange(GraphicsItemChange change, const QVariant &
return super::itemChange(change, value);
}
+void NodeViewContext::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ bool clicked_inside_titlebar = (event->pos().y() < last_titlebar_height_);
+
+ setFlag(ItemIsMovable, clicked_inside_titlebar);
+ setFlag(ItemIsSelectable, clicked_inside_titlebar);
+
+ super::mousePressEvent(event);
+}
+
NodeViewEdge* NodeViewContext::AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to)
{
NodeViewEdge* edge_ui = new NodeViewEdge(output, input, from, to, this);
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
index a5141e32b..cf35b6fd2 100644
--- a/app/widget/nodeview/nodeviewcontext.h
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -30,6 +30,8 @@ public:
protected:
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
+
private:
NodeViewEdge *AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to);
@@ -41,6 +43,8 @@ private:
bool curved_edges_;
+ int last_titlebar_height_;
+
};
}
diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp
index 5498fbefb..f6df8ce73 100644
--- a/app/widget/nodeview/nodeviewedge.cpp
+++ b/app/widget/nodeview/nodeviewedge.cpp
@@ -60,7 +60,7 @@ void NodeViewEdge::Adjust()
{
// Draw a line between the two
SetPoints(from_item()->GetOutputPoint(),
- to_item()->GetInputPoint(input_.input(), input_.element(), from_item()->pos()),
+ to_item()->GetInputPoint(input_.input(), input_.element()),
to_item()->IsExpanded());
}
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 2eb766863..520d2c961 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -67,7 +67,6 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height);
setRect(title_bar_rect_);
- input_connector_ = new NodeViewItemConnector(this);
output_connector_ = new NodeViewItemConnector(this);
}
@@ -219,6 +218,8 @@ void NodeViewItem::SetNode(Node *n)
node_inputs_.clear();
+ ClearInputConnectors();
+
if (node_) {
node_->Retranslate();
@@ -228,7 +229,7 @@ void NodeViewItem::SetNode(Node *n)
}
}
- input_connector_->setVisible(!node_inputs_.isEmpty());
+ UpdateInputConnectors();
connect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
connect(n, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged);
@@ -246,7 +247,6 @@ 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
@@ -263,13 +263,15 @@ void NodeViewItem::SetExpanded(bool e, bool hide_titlebar)
setRect(title_bar_rect_);
}
- update();
+ UpdateInputConnectorFlowDirections();
UpdateConnectorPositions();
ReadjustAllEdges();
UpdateContextRect();
+
+ update();
}
void NodeViewItem::ToggleExpanded()
@@ -403,6 +405,8 @@ QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons
void NodeViewItem::ReadjustAllEdges()
{
+ UpdateInputConnectorFlowDirections();
+ UpdateInputConnectorPositions();
foreach (NodeViewEdge* edge, edges_) {
edge->Adjust();
}
@@ -502,13 +506,15 @@ QRectF NodeViewItem::GetInputRect(int index) const
return r;
}
-QPointF NodeViewItem::GetInputPoint(const QString &input, int element, const QPointF& source_pos) const
+QPointF NodeViewItem::GetInputPoint(const QString &input, int element) const
{
- if (expanded_) {
- return pos() + GetInputPointInternal(node_inputs_.indexOf(input), source_pos);
- } else {
- return pos() + input_connector_->pos();
+ int index = node_inputs_.indexOf(input);
+
+ if (index < 0 || index >= int(input_connectors_.size())) {
+ return QPointF();
}
+
+ return pos() + input_connectors_[index]->pos();
}
QPointF NodeViewItem::GetOutputPoint() const
@@ -539,64 +545,101 @@ void NodeViewItem::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
flow_dir_ = dir;
- input_connector_->SetFlowDirection(dir);
+ UpdateInputConnectorFlowDirections();
output_connector_->SetFlowDirection(dir);
UpdateConnectorPositions();
UpdateNodePosition();
}
-QPointF NodeViewItem::GetInputPointInternal(int index, const QPointF& source_pos) const
-{
- QRectF input_rect = GetInputRect(index);
-
- Qt::Orientation flow_orientation = NodeViewCommon::GetFlowOrientation(flow_dir_);
-
- if (flow_orientation == Qt::Horizontal || IsExpanded()) {
- if (flow_dir_ == NodeViewCommon::kLeftToRight
- || (flow_orientation == Qt::Vertical && source_pos.x() < pos().x())) {
- return QPointF(input_rect.left(), input_rect.center().y());
- } else {
- return QPointF(input_rect.right(), input_rect.center().y());
- }
- } else {
- if (flow_dir_ == NodeViewCommon::kTopToBottom) {
- return QPointF(input_rect.center().x(), input_rect.top());
- } else {
- return QPointF(input_rect.center().x(), input_rect.bottom());
- }
- }
-}
-
void NodeViewItem::UpdateNodePosition()
{
setPos(NodeToScreenPoint(cached_node_pos_, flow_dir_));
}
+void NodeViewItem::UpdateInputConnectors()
+{
+ int old_sz = input_connectors_.size();
+
+ input_connectors_.resize(node_inputs_.size());
+ for (size_t i=old_sz; i(this);
+ }
+}
+
+void NodeViewItem::ClearInputConnectors()
+{
+ input_connectors_.clear();
+}
+
void NodeViewItem::UpdateConnectorPositions()
{
- QRectF output_rect = output_connector_->boundingRect();
+ UpdateInputConnectorPositions();
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());
+ output_connector_->setPos(rect().right(), title_bar_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());
+ output_connector_->setPos(rect().left(), title_bar_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::UpdateInputConnectorPositions()
+{
+ QRectF output_rect = output_connector_->boundingRect();
+
+ // Input connector flow directions change conditionally
+ for (size_t i=0; isetPos(rect().left() - output_rect.width(), GetInputRect(i).center().y());
+ break;
+ case NodeViewCommon::kRightToLeft:
+ input_connectors_[i]->setPos(rect().right() + output_rect.width(), GetInputRect(i).center().y());
+ break;
+ case NodeViewCommon::kTopToBottom:
+ input_connectors_[i]->setPos(rect().center().x(), rect().top() - output_rect.height());
+ break;
+ case NodeViewCommon::kBottomToTop:
+ input_connectors_[i]->setPos(rect().center().x(), rect().bottom() + output_rect.height());
+ break;
+ }
+ }
+}
+
+void NodeViewItem::UpdateInputConnectorFlowDirections()
+{
+ for (size_t i=0; iSetFlowDirection(GetFlowDirectionForInput(i));
+ }
+}
+
+NodeViewCommon::FlowDirection NodeViewItem::GetFlowDirectionForInput(int index)
+{
+ if (!expanded_ || NodeViewCommon::IsFlowHorizontal(flow_dir_)) {
+ return flow_dir_;
+ } else {
+ foreach (NodeViewEdge *edge, edges_) {
+ if (edge->input().input() == node_inputs_.at(index)) {
+ if (edge->from_item()->x() < this->x()) {
+ return NodeViewCommon::kLeftToRight;
+ } else {
+ return NodeViewCommon::kRightToLeft;
+ }
+ }
+ }
+ return NodeViewCommon::kLeftToRight;
+ }
+}
+
void NodeViewItem::NodeAppearanceChanged()
{
update();
diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h
index bd2cd7ac1..c1ff35387 100644
--- a/app/widget/nodeview/nodeviewitem.h
+++ b/app/widget/nodeview/nodeviewitem.h
@@ -80,7 +80,7 @@ public:
/**
* @brief Returns GLOBAL point that edges should connect to for any NodeParam member of this object
*/
- QPointF GetInputPoint(const QString& input, int element, const QPointF &source_pos) const;
+ QPointF GetInputPoint(const QString& input, int element) const;
QPointF GetOutputPoint() const;
@@ -156,18 +156,22 @@ private:
*/
QRectF GetInputRect(int index) const;
- /**
- * @brief Returns local point that edges should connect to for a NodeInput in array node_inputs_[index]
- */
- QPointF GetInputPointInternal(int index, const QPointF &source_pos) const;
-
/**
* @brief Internal update function when logical position changes
*/
void UpdateNodePosition();
+ void UpdateInputConnectors();
+
+ void ClearInputConnectors();
+
void UpdateConnectorPositions();
+ void UpdateInputConnectorPositions();
+ void UpdateInputConnectorFlowDirections();
+
+ NodeViewCommon::FlowDirection GetFlowDirectionForInput(int index);
+
/**
* @brief Reference to attached Node
*/
@@ -203,7 +207,7 @@ private:
bool prevent_removing_;
- NodeViewItemConnector *input_connector_;
+ std::vector > input_connectors_;
NodeViewItemConnector *output_connector_;
bool label_as_output_;
From 854ca0a7a9f77a42211a6fd826645b77f01b5752 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Fri, 12 Nov 2021 11:51:13 -0800
Subject: [PATCH 05/34] reimplemented edge connect/disconnect
---
app/widget/nodeview/nodeview.cpp | 35 +++++------
app/widget/nodeview/nodeviewedge.cpp | 23 +------
app/widget/nodeview/nodeviewedge.h | 11 ----
app/widget/nodeview/nodeviewitem.cpp | 61 ++++++++++++-------
app/widget/nodeview/nodeviewitem.h | 11 ++--
app/widget/nodeview/nodeviewitemconnector.cpp | 5 +-
app/widget/nodeview/nodeviewitemconnector.h | 11 +++-
7 files changed, 75 insertions(+), 82 deletions(-)
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index d5e85fcfb..31be310c6 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -473,30 +473,27 @@ void NodeView::mousePressEvent(QMouseEvent *event)
{
if (HandPress(event)) return;
+ QGraphicsItem* item = itemAt(event->pos());
+
if (event->button() == Qt::LeftButton) {
- // See if we're dragging the arrow of an edge
- QPointF scene_pt = mapToScene(event->pos());
-
- for (NodeViewEdge *edge_item : scene_.edges()) {
- if (edge_item->arrow_bounding_rect().contains(scene_pt)) {
- create_edge_src_ = scene_.NodeToUIObject(edge_item->output());
- create_edge_ = edge_item;
- create_edge_already_exists_ = true;
+ // Determine if user clicked on a connector
+ if (NodeViewItemConnector *connector = dynamic_cast(item)) {
+ NodeViewItem *attached_item = static_cast(connector->parentItem());
+ if (connector->IsOutput()) {
+ CreateNewEdge(attached_item, event->pos());
return;
- }
- }
-
- // See if we're dragging the arrow of a node
- for (NodeViewItem *node_item : scene_.item_map()) {
- if (node_item->GetOutputTriangle().boundingRect().translated(node_item->pos()).contains(scene_pt)) {
- CreateNewEdge(node_item, event->pos());
+ } else {
+ NodeViewEdge *edge_item = attached_item->GetEdgeFromInputConnector(connector);
+ if (edge_item) {
+ create_edge_src_ = edge_item->from_item();
+ create_edge_ = edge_item;
+ create_edge_already_exists_ = true;
+ }
return;
}
}
}
- QGraphicsItem* item = itemAt(event->pos());
-
if (event->button() == Qt::RightButton) {
if (!item || !item->isSelected()) {
// Qt doesn't do this by default for some reason
@@ -668,13 +665,13 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
// Update contexts
- if (!removed_edges.empty()) {
+ /*if (!removed_edges.empty()) {
UpdateContextsFromEdgeRemove(command, removed_edges);
}
if (added_edge.first) {
UpdateContextsFromEdgeAdd(command, added_edge, removed_edges);
- }
+ }*/
Core::instance()->undo_stack()->pushIfHasChildren(command);
return;
diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp
index f6df8ce73..977b88cbd 100644
--- a/app/widget/nodeview/nodeviewedge.cpp
+++ b/app/widget/nodeview/nodeviewedge.cpp
@@ -126,13 +126,6 @@ void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
painter->setPen(QPen(edge_color, edge_width_));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path());
-
- // Draw arrow
- if (!connected_) {
- painter->setPen(Qt::NoPen);
- painter->setBrush(edge_color);
- painter->drawPolygon(arrow_);
- }
}
void NodeViewEdge::Init()
@@ -149,7 +142,6 @@ void NodeViewEdge::Init()
// Use font metrics to set edge width for basic high DPI support
edge_width_ = QFontMetrics(QFont()).height() / 12;
- arrow_size_ = QFontMetrics(QFont()).height() / 2;
}
void NodeViewEdge::UpdateCurve()
@@ -185,7 +177,7 @@ void NodeViewEdge::UpdateCurve()
path.cubicTo(cp1, cp2, end);
if (!qFuzzyCompare(start.x(), end.x())) {
- double continue_x = end.x() - qCos(angle)*arrow_size_;
+ double continue_x = end.x() - qCos(angle);
double x1 = start.x();
double x2 = cp1.x();
@@ -215,18 +207,7 @@ void NodeViewEdge::UpdateCurve()
}
- setPath(path);
-
- const double arrow_angle = 150.0 * M_PI / 180.0;
- QVector arrow_points(4);
- arrow_points[0] = end;
- arrow_points[1] = end + QPointF(qCos(angle + arrow_angle) * arrow_size_, qSin(angle + arrow_angle) * arrow_size_);
- arrow_points[2] = end + QPointF(qCos(angle - arrow_angle) * arrow_size_, qSin(angle - arrow_angle) * arrow_size_);
- arrow_points[3] = end;
-
- arrow_ = QPolygonF(arrow_points);
- arrow_bounding_rect_ = arrow_.boundingRect();
- arrow_bounding_rect_.adjust(-arrow_size_, -arrow_size_, arrow_size_, arrow_size_);
+ setPath(mapFromScene(path));
}
}
diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h
index 6240aeb64..de8d10720 100644
--- a/app/widget/nodeview/nodeviewedge.h
+++ b/app/widget/nodeview/nodeviewedge.h
@@ -70,11 +70,6 @@ public:
return to_item_;
}
- const QRectF arrow_bounding_rect() const
- {
- return arrow_bounding_rect_;
- }
-
void Adjust();
/**
@@ -144,12 +139,6 @@ private:
bool curved_;
- QPolygonF arrow_;
-
- int arrow_size_;
-
- QRectF arrow_bounding_rect_;
-
QPointF cached_start_;
QPointF cached_end_;
bool cached_input_is_expanded_;
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 520d2c961..b3e4ee4e9 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -67,7 +67,7 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height);
setRect(title_bar_rect_);
- output_connector_ = new NodeViewItemConnector(this);
+ output_connector_ = new NodeViewItemConnector(true, this);
}
QPointF NodeViewItem::GetNodePosition() const
@@ -196,7 +196,7 @@ void NodeViewItem::RemoveEdge(NodeViewEdge *edge)
int NodeViewItem::GetIndexAt(QPointF pt) const
{
- pt -= pos();
+ pt -= this->scenePos();
for (int i=0; iRetranslate();
@@ -473,6 +472,17 @@ void NodeViewItem::DrawNodeTitle(QPainter* painter, QString text, const QRectF&
text);
}
+NodeViewEdge *NodeViewItem::GetEdgeFromInputIndex(int index)
+{
+ foreach (NodeViewEdge *edge, edges_) {
+ if (edge->input().input() == node_inputs_.at(index)) {
+ return edge;
+ }
+ }
+
+ return nullptr;
+}
+
void NodeViewItem::SetHighlightedIndex(int index)
{
if (highlighted_index_ == index) {
@@ -491,6 +501,23 @@ void NodeViewItem::SetLabelAsOutput(bool e)
update();
}
+NodeViewEdge *NodeViewItem::GetEdgeFromInputConnector(NodeViewItemConnector *connector)
+{
+ ssize_t index = -1;
+ for (ssize_t i=0; ipos();
+ return input_connectors_[index]->scenePos();
}
QPointF NodeViewItem::GetOutputPoint() const
{
- QPointF p = pos() + output_connector_->pos();
+ QPointF p = output_connector_->scenePos();
QRectF r = output_connector_->boundingRect();
switch (flow_dir_) {
@@ -563,15 +590,10 @@ void NodeViewItem::UpdateInputConnectors()
input_connectors_.resize(node_inputs_.size());
for (size_t i=old_sz; i(this);
+ input_connectors_[i] = std::make_unique(false, this);
}
}
-void NodeViewItem::ClearInputConnectors()
-{
- input_connectors_.clear();
-}
-
void NodeViewItem::UpdateConnectorPositions()
{
UpdateInputConnectorPositions();
@@ -627,16 +649,13 @@ NodeViewCommon::FlowDirection NodeViewItem::GetFlowDirectionForInput(int index)
if (!expanded_ || NodeViewCommon::IsFlowHorizontal(flow_dir_)) {
return flow_dir_;
} else {
- foreach (NodeViewEdge *edge, edges_) {
- if (edge->input().input() == node_inputs_.at(index)) {
- if (edge->from_item()->x() < this->x()) {
- return NodeViewCommon::kLeftToRight;
- } else {
- return NodeViewCommon::kRightToLeft;
- }
- }
+ NodeViewEdge *edge = GetEdgeFromInputIndex(index);
+
+ if (!edge || edge->from_item()->x() < this->x()) {
+ return NodeViewCommon::kLeftToRight;
+ } else {
+ return NodeViewCommon::kRightToLeft;
}
- return NodeViewCommon::kLeftToRight;
}
}
diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h
index c1ff35387..0f11574ed 100644
--- a/app/widget/nodeview/nodeviewitem.h
+++ b/app/widget/nodeview/nodeviewitem.h
@@ -127,13 +127,10 @@ public:
return prevent_removing_;
}
- QPolygonF GetOutputTriangle() const
- {
- return output_connector_->polygon();
- }
-
void SetLabelAsOutput(bool e);
+ NodeViewEdge *GetEdgeFromInputConnector(NodeViewItemConnector *connector);
+
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
@@ -151,6 +148,8 @@ private:
void DrawNodeTitle(QPainter *painter, QString text, const QRectF &rect, Qt::Alignment vertical_align, int icon_size, bool draw_arrow);
+ NodeViewEdge *GetEdgeFromInputIndex(int index);
+
/**
* @brief Returns local rect of a NodeInput in array node_inputs_[index]
*/
@@ -163,8 +162,6 @@ private:
void UpdateInputConnectors();
- void ClearInputConnectors();
-
void UpdateConnectorPositions();
void UpdateInputConnectorPositions();
diff --git a/app/widget/nodeview/nodeviewitemconnector.cpp b/app/widget/nodeview/nodeviewitemconnector.cpp
index 650c33ccf..2ab919d77 100644
--- a/app/widget/nodeview/nodeviewitemconnector.cpp
+++ b/app/widget/nodeview/nodeviewitemconnector.cpp
@@ -29,8 +29,9 @@
namespace olive {
-NodeViewItemConnector::NodeViewItemConnector(QGraphicsItem *parent) :
- QGraphicsPolygonItem(parent)
+NodeViewItemConnector::NodeViewItemConnector(bool is_output, QGraphicsItem *parent) :
+ QGraphicsPolygonItem(parent),
+ output_(is_output)
{
QColor c = qApp->palette().text().color();
setPen(QPen(c, NodeViewItem::DefaultItemBorder()));
diff --git a/app/widget/nodeview/nodeviewitemconnector.h b/app/widget/nodeview/nodeviewitemconnector.h
index 6dfc7d9d3..4da1e2fca 100644
--- a/app/widget/nodeview/nodeviewitemconnector.h
+++ b/app/widget/nodeview/nodeviewitemconnector.h
@@ -30,9 +30,18 @@ namespace olive {
class NodeViewItemConnector : public QGraphicsPolygonItem
{
public:
- NodeViewItemConnector(QGraphicsItem *parent = nullptr);
+ NodeViewItemConnector(bool is_output, QGraphicsItem *parent = nullptr);
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
+
+ bool IsOutput() const
+ {
+ return output_;
+ }
+
+private:
+ bool output_;
+
};
}
From 93be94bc2cb89fdf97e7b4131ac0da22c4e1390e Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Tue, 16 Nov 2021 23:58:34 -0800
Subject: [PATCH 06/34] more work
---
app/core.cpp | 2 +-
app/node/graph.cpp | 53 +-
app/node/graph.h | 53 --
app/node/node.cpp | 189 ++---
app/node/node.h | 178 +----
app/node/nodecopypaste.cpp | 6 +-
app/node/output/track/track.cpp | 2 +-
app/node/param.cpp | 9 +
app/node/param.h | 2 +
app/node/project/folder/folder.cpp | 22 +-
app/node/project/folder/folder.h | 8 +-
app/node/project/project.cpp | 27 +-
app/node/project/sequence/sequence.cpp | 2 +-
app/panel/node/node.cpp | 1 +
app/panel/node/node.h | 20 +-
app/widget/nodeview/nodeview.cpp | 661 ++----------------
app/widget/nodeview/nodeview.h | 57 +-
app/widget/nodeview/nodeviewcontext.cpp | 162 +++--
app/widget/nodeview/nodeviewcontext.h | 24 +-
app/widget/nodeview/nodeviewedge.cpp | 14 +
app/widget/nodeview/nodeviewedge.h | 2 +
app/widget/nodeview/nodeviewitem.cpp | 12 +-
app/widget/nodeview/nodeviewitem.h | 4 +-
app/widget/nodeview/nodeviewminimap.cpp | 10 +-
app/widget/nodeview/nodeviewminimap.h | 2 +
app/widget/nodeview/nodeviewscene.cpp | 60 +-
app/widget/nodeview/nodeviewscene.h | 5 -
app/widget/timelinewidget/tool/add.cpp | 6 +-
app/widget/timelinewidget/tool/import.cpp | 14 +-
app/widget/timelinewidget/tool/tool.cpp | 2 +
app/widget/timelinewidget/tool/tool.h | 2 +
app/widget/timelinewidget/tool/transition.cpp | 8 +-
.../undo/timelineundogeneral.cpp | 171 ++---
.../timelinewidget/undo/timelineundogeneral.h | 10 +-
.../undo/timelineundopointer.cpp | 21 -
.../timelinewidget/undo/timelineundopointer.h | 1 -
.../timelinewidget/undo/timelineundosplit.cpp | 8 -
.../timelinewidget/undo/timelineundosplit.h | 6 +-
app/window/mainwindow/mainwindow.cpp | 14 +-
39 files changed, 493 insertions(+), 1357 deletions(-)
diff --git a/app/core.cpp b/app/core.cpp
index 48830651a..82a6b98fc 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -437,7 +437,7 @@ void Core::CreateNewSequence()
command->add_child(new NodeAddCommand(active_project, new_sequence));
command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence));
- command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false));
+ command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0)));
// Create and connect default nodes to new sequence
new_sequence->add_default_nodes(command);
diff --git a/app/node/graph.cpp b/app/node/graph.cpp
index a2d04b233..f652340fb 100644
--- a/app/node/graph.cpp
+++ b/app/node/graph.cpp
@@ -44,45 +44,6 @@ void NodeGraph::Clear()
}
}
-qreal NodeGraph::GetNodeContextHeight(Node *context)
-{
- const PositionMap &map = position_map_.value(context);
-
- qreal top = 0, bottom = 0;
-
- foreach (const QPointF &pt, map) {
- top = qMin(pt.y(), top);
- bottom = qMax(pt.y(), bottom);
- }
-
- return bottom - top;
-}
-
-int NodeGraph::GetNumberOfContextsNodeIsIn(Node *node) const
-{
- int count = 0;
-
- for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) {
- if (it.value().contains(node)) {
- count++;
- }
- }
-
- return count;
-}
-
-bool NodeGraph::NodeOutputsToContext(Node *node) const
-{
- for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) {
- const PositionMap &pm = it.value();
- if (pm.contains(node) && node->OutputsTo(it.key(), true)) {
- return true;
- }
- }
-
- return false;
-}
-
void NodeGraph::childEvent(QChildEvent *event)
{
super::childEvent(event);
@@ -116,18 +77,10 @@ void NodeGraph::childEvent(QChildEvent *event)
emit NodeRemoved(node);
emit node->RemovedFromGraph(this);
- for (auto it=position_map_.begin(); it!=position_map_.end(); it++) {
- PositionMap &map = it.value();
- for (auto jt=map.begin(); jt!=map.end(); ) {
- if (jt.key() == node) {
- jt = map.erase(jt);
- emit NodePositionRemoved(node, it.key());
- } else {
- jt++;
- }
- }
+ // Remove from any contexts
+ foreach (Node *context, node_children_) {
+ context->RemoveNodeFromContext(node);
}
-
}
}
}
diff --git a/app/node/graph.h b/app/node/graph.h
index 5e0aa5be2..21c8f023e 100644
--- a/app/node/graph.h
+++ b/app/node/graph.h
@@ -63,55 +63,6 @@ public:
return default_nodes_;
}
- bool NodeMapContainsNode(Node* node, Node* context) const
- {
- return position_map_.value(context).contains(node);
- }
-
- QPointF GetNodePosition(Node* node, Node* context)
- {
- return position_map_.value(context).value(node);
- }
-
- void SetNodePosition(Node* node, Node* context, const QPointF& pos)
- {
- position_map_[context].insert(node, pos);
- emit NodePositionAdded(node, context, pos);
- }
-
- void RemoveNodePosition(Node* node, Node* context)
- {
- PositionMap& map = position_map_[context];
- map.remove(node);
- if (map.isEmpty()) {
- position_map_.remove(context);
- }
- emit NodePositionRemoved(node, context);
- }
-
- bool ContextContainsNode(Node *node, Node *context)
- {
- return position_map_[context].contains(node);
- }
-
- qreal GetNodeContextHeight(Node *context);
-
- using PositionMap = QHash;
-
- const PositionMap &GetNodesForContext(Node *context)
- {
- return position_map_[context];
- }
-
- const QMap &GetPositionMap() const
- {
- return position_map_;
- }
-
- int GetNumberOfContextsNodeIsIn(Node *node) const;
-
- bool NodeOutputsToContext(Node *node) const;
-
signals:
/**
* @brief Signal emitted when a Node is added to the graph
@@ -148,10 +99,6 @@ private:
QVector default_nodes_;
- QMap position_map_;
-
- PositionMap root_position_map_;
-
};
}
diff --git a/app/node/node.cpp b/app/node/node.cpp
index d79710962..b1b45ccf6 100644
--- a/app/node/node.cpp
+++ b/app/node/node.cpp
@@ -243,6 +243,36 @@ QIcon Node::icon() const
return icon::New;
}
+QPointF Node::GetNodePositionInContext(Node *node)
+{
+ return context_positions_.value(node);
+}
+
+bool Node::SetNodePositionInContext(Node *node, const QPointF &pos)
+{
+ bool added = !ContextContainsNode(node);
+ context_positions_.insert(node, pos);
+
+ if (added) {
+ emit NodeAddedToContext(node);
+ }
+
+ emit NodePositionInContextChanged(node, pos);
+
+ return added;
+}
+
+bool Node::RemoveNodeFromContext(Node *node)
+{
+ if (ContextContainsNode(node)) {
+ context_positions_.remove(node);
+ emit NodeRemovedFromContext(node);
+ return true;
+ } else {
+ return false;
+ }
+}
+
Color Node::color() const
{
int c;
@@ -429,6 +459,11 @@ void Node::SaveInput(QXmlStreamWriter *writer, const QString &id) const
writer->writeEndElement(); // subelements
}
+bool Node::IsInputHidden(const QString &input) const
+{
+ return (GetInputFlags(input) & kInputFlagHidden);
+}
+
bool Node::IsInputConnectable(const QString &input) const
{
return !(GetInputFlags(input) & kInputFlagNotConnectable);
@@ -1196,13 +1231,10 @@ Node *Node::CopyNodeAndDependencyGraphMinusItemsInternal(QMap& cre
command->add_child(new NodeSetValueHintCommand(copied_input, node->GetValueHintForInput(input.input(), input.element())));
}
- if (node->parent()->GetPositionMap().contains(node)) {
- // This node is a context, copy the context
- const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- // Add either the copy (if it exists) or the original node to the context
- command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value(), false));
- }
+ const PositionMap &map = node->GetContextPositions();
+ for (auto it=map.cbegin(); it!=map.cend(); it++) {
+ // Add either the copy (if it exists) or the original node to the context
+ command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value()));
}
return copy;
@@ -1229,13 +1261,10 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command)
command->add_child(new NodeCopyInputsCommand(node, copy, true));
- if (node->parent()->GetPositionMap().contains(node)) {
- // This node is a context, copy the context
- const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- // Add to the context
- command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value(), false));
- }
+ const PositionMap &map = node->GetContextPositions();
+ for (auto it=map.cbegin(); it!=map.cend(); it++) {
+ // Add to the context
+ command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value()));
}
}
@@ -2318,119 +2347,58 @@ Project *Node::ArrayResizeCommand::GetRelevantProject() const
return node_->project();
}
-void NodeSetPositionAndShiftSurroundingsCommand::redo()
-{
- if (commands_.isEmpty()) {
- // Move first node
- NodeSetPositionCommand* set_pos_command = new NodeSetPositionCommand(node_, relative_, position_, move_dependencies_);
- set_pos_command->redo_now();
- commands_.append(set_pos_command);
-
- // Get bounding rect
- qreal bounding_rect_sz = 1.0;
- qreal bounding_rect_half_sz = bounding_rect_sz * 0.5;
- QRectF bounding_rect(position_.x() - bounding_rect_half_sz, position_.y() - bounding_rect_half_sz, bounding_rect_sz, bounding_rect_sz);
-
- // Start moving other nodes
- foreach (Node* surrounding, node_->parent()->nodes()) {
- if (surrounding != node_) {
- QPointF surrounding_position = node_->parent()->GetNodePosition(surrounding, relative_);
- if (bounding_rect.contains(surrounding_position)) {
- QPointF new_pos = surrounding_position;
-
- qreal move_rate = 0.50;
-
- if (surrounding_position.y() < position_.y()) {
- move_rate = -move_rate;
- }
-
- new_pos.setY(new_pos.y() + move_rate);
-
- auto sur_command = new NodeSetPositionAndShiftSurroundingsCommand(surrounding, relative_, new_pos, true);
- sur_command->redo();
- commands_.append(sur_command);
- }
- }
- }
- } else {
- for (int i=0; iredo_now();
- }
- }
-}
-
void NodeSetPositionCommand::redo()
{
- graph_ = node_->parent();
- if (!(added_ = !graph_->NodeMapContainsNode(node_, relevant_))) {
- old_pos_ = graph_->GetNodePosition(node_, relevant_);
+ if (!(added_ = !context_->ContextContainsNode(node_))) {
+ old_pos_ = context_->GetNodePositionInContext(node_);
+ }
+
+ if (added_) {
+ context_->SetNodePositionInContext(node_, pos_);
+ } else {
+ move(context_, node_, pos_ - old_pos_, move_deps_);
}
- graph_->SetNodePosition(node_, relevant_, pos_);
}
void NodeSetPositionCommand::undo()
{
if (added_) {
- graph_->RemoveNodePosition(node_, relevant_);
+ context_->RemoveNodeFromContext(node_);
} else {
- graph_->SetNodePosition(node_, relevant_, old_pos_);
+ move(context_, node_, old_pos_ - pos_, move_deps_);
}
}
-void NodeSetPositionAsChildCommand::redo()
+void NodeSetPositionCommand::move(Node *context, Node *node, const QPointF &diff, bool recursive)
{
- if (!sub_command_) {
- // Calculate position of node
- NodeGraph *graph = parent_->parent();
- QPointF pos = graph->GetNodePosition(parent_, relative_);
+ QPointF p = context->GetNodePositionInContext(node);
+ p += diff;
+ context->SetNodePositionInContext(node, p);
- // This is a dependency, so we'll place it one X before
- pos.setX(pos.x() - 1);
-
- // The Y will be calculated using the index and child count
- pos.setY(pos.y() - (double(child_count_)*0.5) + this_index_ + 0.5);
-
- sub_command_ = new MultiUndoCommand();
- if (shift_surroundings_) {
- sub_command_->add_child(new NodeSetPositionAndShiftSurroundingsCommand(node_, relative_, pos, true));
- } else {
- sub_command_->add_child(new NodeSetPositionCommand(node_, relative_, pos, true));
+ if (recursive) {
+ for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
+ Node *output = it->second;
+ if (context->ContextContainsNode(output)) {
+ move(context, output, diff, recursive);
+ }
}
}
-
- sub_command_->redo_now();
-}
-
-void NodeSetPositionToOffsetOfAnotherNodeCommand::redo()
-{
- NodeGraph *graph = node_->parent();
- old_pos_ = graph->GetNodePosition(node_, relative_);
- graph->SetNodePosition(node_, relative_, graph->GetNodePosition(other_node_, relative_) + offset_);
-}
-
-void NodeSetPositionToOffsetOfAnotherNodeCommand::undo()
-{
- NodeGraph *graph = node_->parent();
- graph->SetNodePosition(node_, relative_, old_pos_);
}
void NodeRemovePositionFromContextCommand::redo()
{
- NodeGraph *graph = node_->parent();
-
- contained_ = graph->ContextContainsNode(node_, context_);
+ contained_ = context_->ContextContainsNode(node_);
if (contained_) {
- old_pos_ = graph->GetNodePosition(node_, context_);
- graph->RemoveNodePosition(node_, context_);
+ old_pos_ = context_->GetNodePositionInContext(node_);
+ context_->RemoveNodeFromContext(node_);
}
}
void NodeRemovePositionFromContextCommand::undo()
{
if (contained_) {
- NodeGraph *graph = node_->parent();
- graph->SetNodePosition(node_, context_, old_pos_);
+ context_->SetNodePositionInContext(node_, old_pos_);
}
}
@@ -2438,28 +2406,21 @@ void NodeRemovePositionFromAllContextsCommand::redo()
{
NodeGraph *graph = node_->parent();
- if (points_.empty()) {
- // No points yet, let's see what points we should remove
- auto map = graph->GetPositionMap();
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- if (it.value().contains(node_)) {
- points_.insert({it.key(), it.value().value(node_)});
- }
+ foreach (Node* context, graph->nodes()) {
+ if (context->ContextContainsNode(node_)) {
+ contexts_.insert({context, context->GetNodePositionInContext(node_)});
+ context->RemoveNodeFromContext(node_);
}
}
-
- for (auto it=points_.cbegin(); it!=points_.cend(); it++) {
- graph->RemoveNodePosition(node_, it->first);
- }
}
void NodeRemovePositionFromAllContextsCommand::undo()
{
- NodeGraph *graph = node_->parent();
-
- for (auto it=points_.crbegin(); it!=points_.crend(); it++) {
- graph->SetNodePosition(node_, it->first, it->second);
+ for (auto it = contexts_.crbegin(); it != contexts_.crend(); it++) {
+ it->first->SetNodePositionInContext(node_, it->second);
}
+
+ contexts_.clear();
}
void Node::ValueHint::Hash(QCryptographicHash &hash) const
diff --git a/app/node/node.h b/app/node/node.h
index b22af3fff..fceb08d1c 100644
--- a/app/node/node.h
+++ b/app/node/node.h
@@ -208,6 +208,23 @@ public:
return HasInputWithID(id);
}
+ using PositionMap = QHash;
+ const PositionMap &GetContextPositions() const
+ {
+ return context_positions_;
+ }
+
+ bool ContextContainsNode(Node *node) const
+ {
+ return context_positions_.contains(node);
+ }
+
+ QPointF GetNodePositionInContext(Node *node);
+
+ bool SetNodePositionInContext(Node *node, const QPointF &pos);
+
+ bool RemoveNodeFromContext(Node *node);
+
/**
* @brief Retrieve the color of this node
*/
@@ -248,6 +265,7 @@ public:
void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled);
void SaveInput(QXmlStreamWriter* writer, const QString& id) const;
+ bool IsInputHidden(const QString& input) const;
bool IsInputConnectable(const QString& input) const;
bool IsInputKeyframable(const QString& input) const;
@@ -867,7 +885,8 @@ protected:
kInputFlagNormal = 0x0,
kInputFlagArray = 0x1,
kInputFlagNotKeyframable = 0x2,
- kInputFlagNotConnectable = 0x4
+ kInputFlagNotConnectable = 0x4,
+ kInputFlagHidden = 0x8
};
class InputFlags {
@@ -1037,6 +1056,12 @@ signals:
void RemovedFromGraph(NodeGraph* graph);
+ void NodeAddedToContext(Node *node);
+
+ void NodePositionInContextChanged(Node *node, const QPointF &pos);
+
+ void NodeRemovedFromContext(Node *node);
+
private:
class ArrayInsertCommand : public UndoCommand
{
@@ -1258,6 +1283,8 @@ private:
QMap value_hints_;
+ PositionMap context_positions_;
+
private slots:
/**
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
@@ -1367,10 +1394,10 @@ using NodePtr = std::shared_ptr;
class NodeSetPositionCommand : public UndoCommand
{
public:
- NodeSetPositionCommand(Node* node, Node* relevant, const QPointF& pos, bool move_dependencies_relatively)
+ NodeSetPositionCommand(Node* node, Node* context, const QPointF& pos, bool move_dependencies_relatively = false)
{
node_ = node;
- relevant_ = relevant;
+ context_ = context;
pos_ = pos;
move_deps_ = move_dependencies_relatively;
}
@@ -1386,151 +1413,14 @@ protected:
virtual void undo() override;
private:
+ static void move(Node *context, Node *node, const QPointF &diff, bool recursive);
+
Node* node_;
- Node* relevant_;
+ Node* context_;
QPointF pos_;
QPointF old_pos_;
bool added_;
bool move_deps_;
- NodeGraph *graph_;
-
-};
-
-class NodeSetPositionAndShiftSurroundingsCommand : public UndoCommand
-{
-public:
- NodeSetPositionAndShiftSurroundingsCommand(Node* node, Node *relative, const QPointF& pos, bool move_dependencies_relatively) :
- node_(node),
- relative_(relative),
- position_(pos),
- move_dependencies_(move_dependencies_relatively)
- {}
-
- virtual ~NodeSetPositionAndShiftSurroundingsCommand() override
- {
- qDeleteAll(commands_);
- }
-
- virtual Project * GetRelevantProject() const override
- {
- return node_->project();
- }
-
-protected:
- virtual void redo() override;
-
- virtual void undo() override
- {
- for (int i=commands_.size()-1; i>=0; i--) {
- commands_.at(i)->undo_now();
- }
- }
-
-private:
- Node* node_;
-
- Node *relative_;
-
- QPointF position_;
-
- bool move_dependencies_;
-
- QVector commands_;
-
-};
-
-class NodeSetPositionAsChildCommand : public UndoCommand
-{
-public:
- NodeSetPositionAsChildCommand(Node* node, Node* parent, Node *relative, double this_index, int child_count, bool shift_surroundings) :
- node_(node),
- parent_(parent),
- relative_(relative),
- this_index_(this_index),
- child_count_(child_count),
- shift_surroundings_(shift_surroundings),
- sub_command_(nullptr)
- {
- }
-
- virtual ~NodeSetPositionAsChildCommand() override
- {
- delete sub_command_;
- }
-
- virtual Project * GetRelevantProject() const override
- {
- return node_->project();
- }
-
-protected:
- virtual void redo() override;
-
- virtual void undo() override
- {
- sub_command_->undo_now();
- }
-
-private:
- Node* node_;
- Node* parent_;
- Node *relative_;
-
- double this_index_;
- int child_count_;
-
- bool shift_surroundings_;
-
- MultiUndoCommand* sub_command_;
-
-};
-
-class NodePositionCloseChildGapCommand : public UndoCommand
-{
-public:
- NodePositionCloseChildGapCommand(Node *parent, void *relative, int remove_index, int child_count, bool shift_surroundings);
-
- virtual Project * GetRelevantProject() const override
- {
- return parent_->project();
- }
-
-protected:
- virtual void redo() override;
-
- virtual void undo() override;
-
-private:
- Node *parent_;
-
-};
-
-class NodeSetPositionToOffsetOfAnotherNodeCommand : public UndoCommand
-{
-public:
- NodeSetPositionToOffsetOfAnotherNodeCommand(Node* node, Node* other_node, Node *relative, const QPointF& offset) :
- node_(node),
- other_node_(other_node),
- relative_(relative),
- offset_(offset)
- {}
-
- virtual Project * GetRelevantProject() const override
- {
- return node_->project();
- }
-
-protected:
- virtual void redo() override;
-
- virtual void undo() override;
-
-private:
- Node* node_;
- Node* other_node_;
- Node *relative_;
- QPointF offset_;
- QPointF old_pos_;
};
@@ -1585,7 +1475,7 @@ protected:
private:
Node *node_;
- std::map points_;
+ std::map contexts_;
};
diff --git a/app/node/nodecopypaste.cpp b/app/node/nodecopypaste.cpp
index 2d66d72ae..0de513820 100644
--- a/app/node/nodecopypaste.cpp
+++ b/app/node/nodecopypaste.cpp
@@ -53,11 +53,11 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector &nodes, vo
writer.writeStartElement(QStringLiteral("contexts"));
foreach (Node* n, nodes) {
// Determine if this node is a context
- if (n->parent()->GetPositionMap().contains(n)) {
+ if (!n->GetContextPositions().isEmpty()) {
writer.writeStartElement(QStringLiteral("context"));
writer.writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(n)));
- const NodeGraph::PositionMap &map = n->parent()->GetNodesForContext(n);
+ const Node::PositionMap &map = n->GetContextPositions();
for (auto it=map.cbegin(); it!=map.cend(); it++) {
writer.writeStartElement(QStringLiteral("node"));
Project::SavePosition(&writer, it.key(), it.value());
@@ -220,7 +220,7 @@ QVector NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph,
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
Node *subnode = xml_node_data.node_ptrs.value(jt.key());
if (subnode) {
- command->add_child(new NodeSetPositionCommand(subnode, context, jt.value(), false));
+ command->add_child(new NodeSetPositionCommand(subnode, context, jt.value()));
}
}
}
diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp
index e1cb208d6..9506f4513 100644
--- a/app/node/output/track/track.cpp
+++ b/app/node/output/track/track.cpp
@@ -44,7 +44,7 @@ Track::Track() :
locked_(false),
sequence_(nullptr)
{
- AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable));
+ AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable | kInputFlagHidden));
// Since blocks are time based, we can handle the invalidate timing a little more intelligently
// on our end
diff --git a/app/node/param.cpp b/app/node/param.cpp
index 9f6bd8c4d..f0a685abe 100644
--- a/app/node/param.cpp
+++ b/app/node/param.cpp
@@ -33,6 +33,15 @@ QString NodeInput::name() const
}
}
+bool NodeInput::IsHidden() const
+{
+ if (IsValid()) {
+ return node_->IsInputHidden(input_);
+ } else {
+ return false;
+ }
+}
+
bool NodeInput::IsConnected() const
{
if (IsValid()) {
diff --git a/app/node/param.h b/app/node/param.h
index 63aa413f7..3de4b6727 100644
--- a/app/node/param.h
+++ b/app/node/param.h
@@ -115,6 +115,8 @@ public:
return node_ && !input_.isEmpty() && element_ >= -1;
}
+ bool IsHidden() const;
+
bool IsConnected() const;
bool IsKeyframing() const;
diff --git a/app/node/project/folder/folder.cpp b/app/node/project/folder/folder.cpp
index feae6d612..7b017923f 100644
--- a/app/node/project/folder/folder.cpp
+++ b/app/node/project/folder/folder.cpp
@@ -113,19 +113,12 @@ void Folder::InputDisconnectedEvent(const QString &input, int element, Node *out
}
}
-FolderAddChild::FolderAddChild(Folder *folder, Node *child, bool autoposition) :
+FolderAddChild::FolderAddChild(Folder *folder, Node *child) :
folder_(folder),
- child_(child),
- autoposition_(autoposition),
- position_command_(nullptr)
+ child_(child)
{
}
-FolderAddChild::~FolderAddChild()
-{
- delete position_command_;
-}
-
Project *FolderAddChild::GetRelevantProject() const
{
return folder_->project();
@@ -136,21 +129,10 @@ void FolderAddChild::redo()
int array_index = folder_->InputArraySize(Folder::kChildInput);
folder_->InputArrayAppend(Folder::kChildInput, false);
Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index));
-
- if (autoposition_) {
- if (!position_command_) {
- position_command_ = new NodeSetPositionAsChildCommand(child_, folder_, folder_->project()->root(), array_index, array_index+1, true);
- }
- position_command_->redo_now();
- }
}
void FolderAddChild::undo()
{
- if (position_command_) {
- position_command_->undo_now();
- }
-
Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1));
folder_->InputArrayRemoveLast(Folder::kChildInput);
}
diff --git a/app/node/project/folder/folder.h b/app/node/project/folder/folder.h
index 1303ce7d7..12677e57b 100644
--- a/app/node/project/folder/folder.h
+++ b/app/node/project/folder/folder.h
@@ -208,9 +208,7 @@ private:
class FolderAddChild : public UndoCommand
{
public:
- FolderAddChild(Folder* folder, Node* child, bool autoposition = true);
-
- virtual ~FolderAddChild() override;
+ FolderAddChild(Folder* folder, Node* child);
virtual Project * GetRelevantProject() const override;
@@ -224,10 +222,6 @@ private:
Node* child_;
- bool autoposition_;
-
- NodeSetPositionAsChildCommand* position_command_;
-
};
}
diff --git a/app/node/project/project.cpp b/app/node/project/project.cpp
index f865e28c8..64d7cb107 100644
--- a/app/node/project/project.cpp
+++ b/app/node/project/project.cpp
@@ -44,19 +44,16 @@ Project::Project() :
root_->setParent(this);
root_->SetLabel(tr("Root"));
root_->SetCanBeDeleted(false);
- SetNodePosition(root_, root_, QPointF(0, 0));
// Adds a color manager "node" to this project so that it synchronizes
color_manager_ = new ColorManager();
color_manager_->setParent(this);
- SetNodePosition(color_manager_, root_, QPointF(1, 0));
color_manager_->SetCanBeDeleted(false);
AddDefaultNode(color_manager_);
// Same with project settings
settings_ = new ProjectSettingsNode();
settings_->setParent(this);
- SetNodePosition(settings_, root_, QPointF(2, 0));
settings_->SetCanBeDeleted(false);
AddDefaultNode(settings_);
@@ -167,7 +164,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint
Node *node = xml_node_data.node_ptrs.value(node_ptr);
if (node) {
- SetNodePosition(node, context, node_pos);
+ context->SetNodePositionInContext(node, node_pos);
} else {
qWarning() << "Failed to find pointer for node position";
reader->skipCurrentElement();
@@ -230,20 +227,22 @@ void Project::Save(QXmlStreamWriter *writer) const
writer->writeStartElement(QStringLiteral("positions"));
- for (auto it=GetPositionMap().cbegin(); it!=GetPositionMap().cend(); it++) {
- writer->writeStartElement(QStringLiteral("context"));
+ foreach (Node* context, nodes()) {
+ const Node::PositionMap &map = context->GetContextPositions();
- writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(it.key())));
+ if (!map.isEmpty()) {
+ writer->writeStartElement(QStringLiteral("context"));
- const PositionMap &map = it.value();
+ writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(context)));
- for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
- writer->writeStartElement(QStringLiteral("node"));
- SavePosition(writer, jt.key(), jt.value());
- writer->writeEndElement(); // node
+ for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
+ writer->writeStartElement(QStringLiteral("node"));
+ SavePosition(writer, jt.key(), jt.value());
+ writer->writeEndElement(); // node
+ }
+
+ writer->writeEndElement(); // context
}
-
- writer->writeEndElement(); // context
}
writer->writeEndElement(); // positions
diff --git a/app/node/project/sequence/sequence.cpp b/app/node/project/sequence/sequence.cpp
index 27b17708f..0cb443188 100644
--- a/app/node/project/sequence/sequence.cpp
+++ b/app/node/project/sequence/sequence.cpp
@@ -41,7 +41,7 @@ Sequence::Sequence()
// Create track input
QString track_input_id = kTrackInputFormat.arg(i);
- AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray));
+ AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden));
IgnoreInvalidationsFrom(track_input_id);
diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp
index 591f7a867..3f0e3a4a2 100644
--- a/app/panel/node/node.cpp
+++ b/app/panel/node/node.cpp
@@ -38,6 +38,7 @@ NodePanel::NodePanel(QWidget *parent) :
// Create NodeView widget
node_view_ = new NodeView(this);
outer_layout->addWidget(node_view_);
+ connect(this, &NodePanel::visibilityChanged, node_view_, &NodeView::CenterOnItemsBoundingRect);
// Connect toolbar to NodeView
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
diff --git a/app/panel/node/node.h b/app/panel/node/node.h
index d145bb91d..20eccc79a 100644
--- a/app/panel/node/node.h
+++ b/app/panel/node/node.h
@@ -36,20 +36,15 @@ class NodePanel : public PanelWidget
public:
NodePanel(QWidget* parent);
- NodeGraph* GetGraph() const
+ void SetContexts(const QVector &nodes)
{
- return node_view_->GetGraph();
+ node_view_->SetContexts(nodes);
+ toolbar_->setEnabled(!nodes.isEmpty());
}
- void SetGraph(NodeGraph *graph, const QVector &nodes)
+ void CloseContextsBelongingToProject(Project *project)
{
- node_view_->SetGraph(graph, nodes);
- toolbar_->setEnabled(graph);
- }
-
- void ClearGraph()
- {
- node_view_->ClearGraph();
+ node_view_->CloseContextsBelongingToProject(project);
}
const QVector &GetCurrentContexts() const
@@ -113,11 +108,6 @@ public slots:
node_view_->Select(nodes, center_view_on_item);
}
- void SelectWithDependencies(const QVector& nodes, bool center_view_on_item)
- {
- node_view_->SelectWithDependencies(nodes, center_view_on_item);
- }
-
signals:
void NodesSelected(const QVector& nodes);
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index 31be310c6..4c8385d9d 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -42,15 +42,13 @@ const double NodeView::kMinimumScale = 0.1;
NodeView::NodeView(QWidget *parent) :
HandMovableView(parent),
- graph_(nullptr),
drop_edge_(nullptr),
create_edge_(nullptr),
create_edge_dst_(nullptr),
create_edge_dst_temp_expanded_(false),
paste_command_(nullptr),
- filter_mode_(kFilterShowSelective),
scale_(1.0),
- queue_reposition_contexts_(false)
+ first_show_(true)
{
setScene(&scene_);
SetDefaultDragMode(RubberBandDrag);
@@ -84,10 +82,10 @@ NodeView::~NodeView()
ClearGraph();
}
-void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes)
+void NodeView::SetContexts(const QVector &nodes)
{
// Remove contexts that are no longer in the list
- foreach (Node *n, filter_nodes_) {
+ foreach (Node *n, contexts_) {
if (!nodes.contains(n)) {
scene_.RemoveContext(n);
}
@@ -95,86 +93,38 @@ void NodeView::SetGraph(NodeGraph *graph, const QVector &nodes)
// Add contexts that are now in the list
foreach (Node *n, nodes) {
- if (!filter_nodes_.contains(n)) {
+ if (!contexts_.contains(n)) {
scene_.AddContext(n);
}
}
- filter_nodes_ = nodes;
+ contexts_ = nodes;
- /*bool graph_changed = graph_ != graph;
- bool context_changed = last_set_filter_nodes_ != nodes;
+ CenterOnItemsBoundingRect();
+}
- 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);
+void NodeView::CloseContextsBelongingToProject(Project *project)
+{
+ QVector new_contexts = contexts_;
- if (refresh_required) {
- DeselectAll();
- positions_.clear();
- scene_.clear();
- context_offsets_.clear();
+ for (auto it = new_contexts.begin(); it != new_contexts.end(); ) {
+ if ((*it)->project() == project) {
+ it = new_contexts.erase(it);
+ } else {
+ it++;
}
+ }
- // Handle graph change
- if (graph_changed) {
- if (graph_) {
- // Disconnect from current graph
- 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::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) {
- last_set_filter_nodes_ = nodes;
-
- if (filter_mode_ == kFilterShowSelective) {
- filter_nodes_ = nodes;
- }
- }
-
- if (refresh_required && nodes_visible) {
- if (filter_mode_ == kFilterShowAll) {
- // Just make the filter nodes all of the graph's contexts
- filter_nodes_ = graph->GetPositionMap().keys().toVector();
- }
-
- RepositionContexts();
-
- // Center on something
- QMetaObject::invokeMethod(this, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
- }
- }*/
+ SetContexts(new_contexts);
}
void NodeView::ClearGraph()
{
- SetGraph(nullptr, QVector());
+ SetContexts(QVector());
}
void NodeView::DeleteSelected()
{
- if (!graph_) {
- return;
- }
-
MultiUndoCommand* command = new MultiUndoCommand();
{
@@ -189,9 +139,6 @@ void NodeView::DeleteSelected()
command->add_child(new NodeEdgeRemoveCommand(edge->output(), edge->input()));
removed_connections[i] = {edge->output(), edge->input()};
}
-
- // Update contexts
- UpdateContextsFromEdgeRemove(command, removed_connections);
}
}
@@ -219,10 +166,6 @@ void NodeView::DeleteSelected()
void NodeView::SelectAll()
{
- if (!graph_) {
- return;
- }
-
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
@@ -249,7 +192,7 @@ void NodeView::SelectAll()
void NodeView::DeselectAll()
{
- if (!graph_ || selected_nodes_.isEmpty()) {
+ if (selected_nodes_.isEmpty()) {
return;
}
@@ -268,10 +211,6 @@ void NodeView::DeselectAll()
void NodeView::Select(QVector nodes, bool center_view_on_item)
{
- if (!graph_) {
- return;
- }
-
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
@@ -331,39 +270,13 @@ void NodeView::Select(QVector nodes, bool center_view_on_item)
selected_nodes_ = nodes;
}
-void NodeView::SelectWithDependencies(QVector nodes, bool center_view_on_item)
-{
- if (!graph_) {
- return;
- }
-
- int original_length = nodes.size();
- for (int i=0;i dependencies = nodes.at(i)->GetDependencies();
-
- foreach (Node *d, dependencies) {
- if (scene_.item_map().contains(d) && !nodes.contains(d)) {
- nodes.append(d);
- }
- }
- }
-
- Select(nodes, center_view_on_item);
-}
-
void NodeView::CopySelected(bool cut)
{
- if (!graph_) {
+ if (selected_nodes_.isEmpty()) {
return;
}
- QVector selected = scene_.GetSelectedNodes();
-
- if (selected.isEmpty()) {
- return;
- }
-
- CopyNodesToClipboard(selected);
+ CopyNodesToClipboard(selected_nodes_);
if (cut) {
DeleteSelected();
@@ -409,43 +322,41 @@ void NodeView::keyPressEvent(QKeyEvent *event)
case Qt::Key_Up:
case Qt::Key_Down:
{
- if (graph_) {
- MultiUndoCommand *pos_command = new MultiUndoCommand();
- for (Node *n : qAsConst(selected_nodes_)) {
- for (Node *context : qAsConst(filter_nodes_)) {
- if (graph_->GetNodesForContext(context).contains(n)) {
- QPointF old_pos = graph_->GetNodePosition(n, context);
+ MultiUndoCommand *pos_command = new MultiUndoCommand();
+ for (Node *n : qAsConst(selected_nodes_)) {
+ for (Node *context : qAsConst(contexts_)) {
+ if (context->ContextContainsNode(n)) {
+ QPointF old_pos = context->GetNodePositionInContext(n);
- // Determine one pixel in scene units
- double movement_amt = 1.0 / scale_;
+ // Determine one pixel in scene units
+ double movement_amt = 1.0 / scale_;
- // Translate to 2D movement
- QPointF node_movement;
- switch (event->key()) {
- case Qt::Key_Left:
- node_movement.setX(-movement_amt);
- break;
- case Qt::Key_Right:
- node_movement.setX(movement_amt);
- break;
- case Qt::Key_Up:
- node_movement.setY(-movement_amt);
- break;
- case Qt::Key_Down:
- node_movement.setY(movement_amt);
- break;
- }
-
- // Translate from screen units into node units
- node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection());
-
- // Move command
- pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement, false));
+ // Translate to 2D movement
+ QPointF node_movement;
+ switch (event->key()) {
+ case Qt::Key_Left:
+ node_movement.setX(-movement_amt);
+ break;
+ case Qt::Key_Right:
+ node_movement.setX(movement_amt);
+ break;
+ case Qt::Key_Up:
+ node_movement.setY(-movement_amt);
+ break;
+ case Qt::Key_Down:
+ node_movement.setY(movement_amt);
+ break;
}
+
+ // Translate from screen units into node units
+ node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection());
+
+ // Move command
+ pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement));
}
}
- Core::instance()->undo_stack()->pushIfHasChildren(pos_command);
}
+ Core::instance()->undo_stack()->pushIfHasChildren(pos_command);
break;
}
case Qt::Key_Escape:
@@ -664,15 +575,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
create_edge_dst_ = nullptr;
}
- // Update contexts
- /*if (!removed_edges.empty()) {
- UpdateContextsFromEdgeRemove(command, removed_edges);
- }
-
- if (added_edge.first) {
- UpdateContextsFromEdgeAdd(command, added_edge, removed_edges);
- }*/
-
Core::instance()->undo_stack()->pushIfHasChildren(command);
return;
}
@@ -689,38 +591,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
}
- {
- // If any node positions changed, set them in their contexts now
- MultiUndoCommand *set_pos_command = new MultiUndoCommand();
- for (auto it=positions_.begin(); it!=positions_.end(); it++) {
- NodeViewItem *item = it.key();
- Position &pos_data = it.value();
- QPointF current_item_pos = item->GetNodePosition();
- Node *node = pos_data.node;
-
- if (pos_data.original_item_pos != current_item_pos) {
- QPointF diff = current_item_pos - pos_data.original_item_pos;
-
- for (Node *context : qAsConst(filter_nodes_)) {
- if (graph_->ContextContainsNode(node, context)) {
- QPointF current_node_pos_in_context = graph_->GetNodePosition(node, context);
- current_node_pos_in_context += diff;
- set_pos_command->add_child(new NodeSetPositionCommand(node, context, current_node_pos_in_context, false));
- }
- }
-
- pos_data.original_item_pos = current_item_pos;
- }
- }
- if (set_pos_command->child_count()) {
- set_pos_command->redo_now();
- command->add_child(set_pos_command);
- } else {
- delete set_pos_command;
- }
- }
-
-
if (!attached_items_.isEmpty()) {
{
// Dropped attached item onto an edge, connect it between them
@@ -757,7 +627,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
bool removed = false;
QVector relevant_contexts;
- for (Node *context : qAsConst(filter_nodes_)) {
+ for (Node *context : qAsConst(contexts_)) {
if (attached_node->OutputsTo(context, true)) {
relevant_contexts.append(context);
} else {
@@ -768,7 +638,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
if (removed && !relevant_contexts.isEmpty()) {
for (Node *relevant : qAsConst(relevant_contexts)) {
- remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant), false));
+ remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant)));
}
remove_pos_command->add_child(remove_pos_subcommand);
@@ -844,7 +714,7 @@ void NodeView::UpdateSelectionCache()
void NodeView::ShowContextMenu(const QPoint &pos)
{
- if (filter_nodes_.isEmpty()) {
+ if (contexts_.isEmpty()) {
return;
}
@@ -896,17 +766,6 @@ void NodeView::ShowContextMenu(const QPoint &pos)
m.addSeparator();
- Menu* filter_menu = new Menu(tr("Filter"), &m);
- m.addMenu(filter_menu);
-
- filter_menu->AddActionWithData(tr("Show All Nodes"), kFilterShowAll, filter_mode_);
-
- filter_menu->AddActionWithData(tr("Show Selected"), kFilterShowSelective, filter_mode_);
-
- connect(filter_menu, &Menu::triggered, this, &NodeView::ContextMenuFilterChanged);
-
-
-
Menu* direction_menu = new Menu(tr("Direction"), &m);
m.addMenu(direction_menu);
@@ -940,23 +799,20 @@ void NodeView::ShowContextMenu(const QPoint &pos)
void NodeView::CreateNodeSlot(QAction *action)
{
- if (!graph_) {
- return;
- }
-
- Node* new_node = NodeFactory::CreateFromMenuAction(action);
+ qDebug() << "STUB!";
+ /*Node* new_node = NodeFactory::CreateFromMenuAction(action);
if (new_node) {
paste_command_ = new MultiUndoCommand();
paste_command_->add_child(new NodeAddCommand(graph_, new_node));
- for (Node *context : qAsConst(filter_nodes_)) {
+ for (Node *context : qAsConst(contexts_)) {
paste_command_->add_child(new NodeSetPositionCommand(new_node, context, QPointF(0, 0), false));
}
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, {new_node}));
paste_command_->redo_now();
this->setFocus();
- }
+ }*/
}
void NodeView::ContextMenuSetDirection(QAction *action)
@@ -964,26 +820,6 @@ void NodeView::ContextMenuSetDirection(QAction *action)
SetFlowDirection(static_cast(action->data().toInt()));
}
-void NodeView::ContextMenuFilterChanged(QAction *action)
-{
- FilterMode mode = static_cast(action->data().toInt());
-
- if (filter_mode_ != mode) {
- // Store temporary graph variables
- NodeGraph *graph = graph_;
- QVector nodes = last_set_filter_nodes_;
-
- // Unset graph with current filter mode
- ClearGraph();
-
- // Change filter mode
- filter_mode_ = mode;
-
- // Re-set graph with new filter mode
- SetGraph(graph, nodes);
- }
-}
-
void NodeView::OpenSelectedNodeInViewer()
{
QVector selected = scene_.GetSelectedNodes();
@@ -994,100 +830,6 @@ void NodeView::OpenSelectedNodeInViewer()
}
}
-// Commenting out because there shouldn't be any situations where a node would be added without
-// being in a context. We're keeping RemoveNode as a fail-safe because it could provide crash
-// resistance where RemoveNodePosition might be missed.
-//void NodeView::AddNode(Node *node)
-//{
-// if (filter_mode_ == kFilterShowAll) {
-// scene_.AddNode(node);
-// }
-//}
-
-void NodeView::RemoveNode(Node *node)
-{
- for (auto it=attached_items_.begin(); it!=attached_items_.end(); ) {
- if (it->item->GetNode() == node) {
- it = attached_items_.erase(it);
- } else {
- it++;
- }
- }
- for (const Node::OutputConnection &oc : node->output_connections()) {
- scene_.RemoveEdge(oc.first, oc.second);
- }
- for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
- scene_.RemoveEdge(it->second, it->first);
- }
- positions_.remove(scene_.item_map().value(node));
-}
-
-void NodeView::AddEdge(Node *output, const NodeInput &input)
-{
- Node *output_node = output;
- Node *input_node = input.node();
-
- if (scene_.item_map().contains(output_node) && scene_.item_map().contains(input_node)) {
- scene_.AddEdge(output, input);
- }
-}
-
-void NodeView::RemoveEdge(Node *output, const NodeInput &input)
-{
- scene_.RemoveEdge(output, input);
-}
-
-void NodeView::AddNodePosition(Node *node, Node *relative)
-{
- bool listening_to_node = filter_nodes_.contains(relative);
-
- if (!listening_to_node) {
- if (filter_mode_ == kFilterShowAll) {
- // We're not listening to this context, but because we're showing all, add it
- filter_nodes_.append(relative);
- } else {
- // Ignore signal
- return;
- }
- }
-
- // Reposition contexts because one of their heights may have changed or a new one may have been
- // added
- UpdateNodeItem(node);
-
- if (filter_mode_ == kFilterShowAll) {
- queue_reposition_contexts_ = true;
- viewport()->update();
- }
-}
-
-void NodeView::RemoveNodePosition(Node *node, Node *relative)
-{
- if (filter_nodes_.contains(relative)) {
- NodeViewItem *item = scene_.item_map().value(node);
-
- if (item && !item->GetPreventRemoving()) {
- // Determine if any other contexts have this node
- bool found = false;
-
- for (Node *context : qAsConst(filter_nodes_)) {
- if (graph_->ContextContainsNode(node, context)) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- RemoveNode(node);
- }
- }
-
- if (filter_mode_ == kFilterShowAll) {
- RepositionContexts();
- }
- }
-}
-
void NodeView::UpdateSceneBoundingRect()
{
// Get current items bounding rect
@@ -1229,13 +971,6 @@ bool NodeView::event(QEvent *event)
bool NodeView::eventFilter(QObject *object, QEvent *event)
{
- if (object == viewport() && event->type() == QEvent::Paint) {
- if (queue_reposition_contexts_) {
- RepositionContexts();
- queue_reposition_contexts_ = false;
- }
- }
-
return super::eventFilter(object, event);
}
@@ -1259,7 +994,8 @@ void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVec
void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata)
{
- NodeGraph::PositionMap *map = static_cast(userdata);
+ qDebug() << "STUB!";
+ /*NodeGraph::PositionMap *map = static_cast(userdata);
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("pos")) {
@@ -1295,7 +1031,7 @@ void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNode
} else {
reader->skipCurrentElement();
}
- }
+ }*/
}
void NodeView::ZoomFromKeyboard(double multiplier)
@@ -1310,148 +1046,6 @@ void NodeView::ZoomFromKeyboard(double multiplier)
ZoomIntoCursorPosition(nullptr, multiplier, cursor_pos);
}
-bool NodeView::DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge)
-{
- // Determines whether `node` outputs to another node in `context` besides `source`
- for (const Node::OutputConnection &conn : node->output_connections()) {
- Node *output_candidate = conn.second.node();
-
- if (output_candidate == source) {
- continue;
- }
-
- if (graph_->ContextContainsNode(output_candidate, context)) {
- if (!output_candidate->OutputsTo(source, true, removed_edges, added_edge)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-void NodeView::UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges)
-{
- // For each edge we remove, determine if we should remove the node from a context as well
- for (const Node::OutputConnection &edge : remove_edges) {
- Node *output_node = edge.first;
- QVector contexts_to_remove_from;
- int contexts_containing = 0;
-
- for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
- Node *context = it.key();
-
- if (it.value().contains(output_node)) {
- bool currently_outputs = output_node->OutputsTo(context, true);
- bool will_output_after_operation = output_node->OutputsTo(context, true, remove_edges);
-
- if (currently_outputs && !will_output_after_operation) {
- // Will remove
- contexts_to_remove_from.append(context);
- }
-
- contexts_containing++;
- }
- }
-
- // Removing from all current contexts, convert to a floating node (i.e. don't remove from the context)
- if (contexts_to_remove_from.size() != contexts_containing) {
- // Not removing from all contexts, can remove
- bool removing_from_all_current_contexts = true;
-
- for (Node *context : qAsConst(filter_nodes_)) {
- if (graph_->ContextContainsNode(output_node, context)) {
- if (!contexts_to_remove_from.contains(context)) {
- removing_from_all_current_contexts = false;
- break;
- }
- }
- }
-
- for (Node *context : qAsConst(contexts_to_remove_from)) {
- RecursivelyRemoveFloatingNodeFromContext(command, output_node, context, output_node, remove_edges, Node::OutputConnection(), removing_from_all_current_contexts);
- }
- }
- }
-}
-
-void NodeView::RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing)
-{
- if (prevent_removing) {
- command->add_child(new NodeViewItemPreventRemovingCommand(this, node, true));
- }
-
- command->add_child(new NodeRemovePositionFromContextCommand(node, context));
-
- // Remove any dependency from the context that's also floating
- for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
- Node *dependency = it->second;
-
- // Determine if this node happens to output to anything else in the context (which may be
- // another floating node that won't be removed by this operation)
- if (!DetermineIfNodeIsFloatingInContext(dependency, context, source, removed_edges, added_edge)) {
- RecursivelyRemoveFloatingNodeFromContext(command, dependency, context, source, removed_edges, added_edge, prevent_removing);
- }
- }
-}
-
-void NodeView::RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context)
-{
- NodeViewItem *item = scene_.item_map().value(node);
-
- if (item) {
- command->add_child(new NodeSetPositionCommand(node, context, GetEstimatedPositionForContext(item, context), false));
-
- // Add dependency
- for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
- Node *dependency = it->second;
- RecursivelyAddNodeToContext(command, dependency, context);
- }
- }
-}
-
-void NodeView::UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges)
-{
- // Determine if node currently does NOT output to a context that it WILL after this operation
- QVector contexts_to_add_to;
- Node *connecting_node = added_edge.first;
- Node *input_node = added_edge.second.node();
- for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
- if (it.value().contains(input_node)) {
- contexts_to_add_to.append(it.key());
- }
- }
-
- if (!contexts_to_add_to.isEmpty()) {
- // Determine whether the node is currently "floating", i.e. it outputs to none of the contexts
- // that it currently belongs to. If so, we will take ownership of it with this node.
- bool node_is_floating = true;
- QVector current_contexts;
- for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
- if (it.value().contains(connecting_node)) {
- if (connecting_node->OutputsTo(it.key(), true, removed_edges)) {
- node_is_floating = false;
- break;
- } else {
- current_contexts.append(it.key());
- }
- }
- }
-
- if (node_is_floating) {
- // This action will unfloat this node, so remove it from all current contexts
- for (Node *context : qAsConst(current_contexts)) {
- RecursivelyRemoveFloatingNodeFromContext(command, connecting_node, context, connecting_node, removed_edges, added_edge, false);
- }
- }
-
- // Add nodes to contexts
- for (Node *context : qAsConst(contexts_to_add_to)) {
- RecursivelyAddNodeToContext(command, connecting_node, context);
- }
- }
-}
-
QPointF NodeView::GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const
{
return item->GetNodePosition() - context_offsets_.value(context);
@@ -1545,86 +1139,6 @@ void NodeView::PositionNewEdge(const QPoint &pos)
create_edge_->SetConnected(create_edge_dst_input_.IsValid());
}
-void NodeView::RepositionContexts()
-{
- // Determine which contexts are root-level
- QVector processing_filters = filter_nodes_;
-
- // Level counter as we iterate through the list a few times
- int level = 0;
-
- // Root-level positioning variables
- qreal last_offset = 0;
- int additional_spacing = 0;
-
- while (!processing_filters.isEmpty()) {
- QVector contexts_on_this_level;
-
- for (int i=0; iContextContainsNode(context, other_context)) {
- this_level = false;
- break;
- }
- }
-
- if (this_level) {
- contexts_on_this_level.append(context);
- }
- }
-
- for (Node *context : qAsConst(contexts_on_this_level)) {
- if (level == 0) {
- const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context);
-
- // First determine the total "height" of this graph and how much we need to offset it
- qreal top = 0;
- qreal bottom = 0;
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- const QPointF &node_pos_in_context = it.value();
- top = qMin(node_pos_in_context.y(), top);
- bottom = qMax(node_pos_in_context.y(), bottom);
- }
-
- last_offset += (additional_spacing + (bottom - top));
- additional_spacing = 1;
- context_offsets_.insert(context, QPointF(0, last_offset));
- } else {
- // Create/update item
- NodeViewItem *item = UpdateNodeItem(context, true);
-
- // Get position generated by UpdateNodeItem
- QPointF context_pos = item->GetNodePosition();
-
- // Adjust by the context node's position in its own context (this will usually be 0,0)
- context_pos -= graph_->GetNodesForContext(context).value(context);
-
- // Insert this context's offset
- context_offsets_.insert(context, context_pos);
- }
-
- // Remove from list so we don't process again
- processing_filters.removeOne(context);
- }
-
- level++;
- }
-
- // Now that we've positioned all the contexts, position all other nodes relative to those contexts
- for (Node *context : qAsConst(filter_nodes_)) {
- const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context);
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- UpdateNodeItem(it.key());
- }
- }
-}
-
void NodeView::GroupNodes()
{
/*NodeGroup *group = new NodeGroup();
@@ -1636,54 +1150,11 @@ void NodeView::UngroupNodes()
//static_cast(selected_nodes_.first());
}
-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) {
- 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);
- }
- }
-
- for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
- if (scene_.item_map().contains(it->second.node())) {
- scene_.AddEdge(it->first, it->second);
- }
- }
- }
-
- // Determine "view" position by averaging the Y value and "min"ing the X value of all contexts
- QPointF item_pos(std::numeric_limits::max(), 0.0);
- int average_count = 0;
- for (Node *context : qAsConst(filter_nodes_)) {
- if (context == node && ignore_own_context) {
- continue;
- }
-
- if (graph_->GetNodesForContext(context).contains(node)) {
- QPointF this_context_pos = graph_->GetNodePosition(node, context);
- this_context_pos += context_offsets_.value(context);
-
- item_pos.setX(qMin(item_pos.x(), this_context_pos.x()));
- item_pos.setY(item_pos.y() + this_context_pos.y());
- average_count++;
- }
- }
- item_pos.setY(item_pos.y() / average_count);
-
- // Set position
- item->SetNodePosition(item_pos);
- positions_.insert(item, {node, item_pos});
-
- return item;
-}
-
void NodeView::PasteNodesInternal(const QVector &duplicate_nodes)
{
+ /*
// If no graph, do nothing
- if (!graph_) {
+ if (contexts_.isEmpty()) {
return;
}
@@ -1696,7 +1167,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes)
new_nodes = PasteNodesFromClipboard(graph_, paste_command_, &map);
for (auto it=new_nodes.cbegin(); it!=new_nodes.cend(); it++) {
- for (Node *context : qAsConst(filter_nodes_)) {
+ for (Node *context : qAsConst(contexts_)) {
paste_command_->add_child(new NodeSetPositionCommand(*it, context, map.value(*it), false));
}
}
@@ -1707,7 +1178,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes)
Node *src = duplicate_nodes.at(i);
Node *copy = new_nodes.at(i);
- for (Node *context : qAsConst(filter_nodes_)) {
+ for (Node *context : qAsConst(contexts_)) {
QPointF p = scene_.item_map().value(src)->GetNodePosition();
paste_command_->add_child(new NodeSetPositionCommand(copy, context, p, false));
}
@@ -1725,6 +1196,7 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes)
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, new_nodes));
paste_command_->redo_now();
+ */
}
NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector &nodes) :
@@ -1745,8 +1217,7 @@ void NodeView::NodeViewAttachNodesToCursor::undo()
Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const
{
- // Will either return a project or a nullptr which is also acceptable
- return dynamic_cast(view_->graph_);
+ return nullptr;
}
void NodeView::NodeViewItemPreventRemovingCommand::redo()
diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h
index 941120361..8616974f5 100644
--- a/app/widget/nodeview/nodeview.h
+++ b/app/widget/nodeview/nodeview.h
@@ -49,12 +49,9 @@ public:
virtual ~NodeView() override;
- NodeGraph* GetGraph() const
- {
- return graph_;
- }
+ void SetContexts(const QVector &nodes);
- void SetGraph(NodeGraph *graph, const QVector &nodes);
+ void CloseContextsBelongingToProject(Project *project);
void ClearGraph();
@@ -67,7 +64,6 @@ public:
void DeselectAll();
void Select(QVector nodes, bool center_view_on_item);
- void SelectWithDependencies(QVector nodes, bool center_view_on_item);
void CopySelected(bool cut);
void Paste();
@@ -82,7 +78,7 @@ public:
const QVector &GetCurrentContexts() const
{
- return filter_nodes_;
+ return contexts_;
}
public slots:
@@ -98,6 +94,8 @@ public slots:
delete m;
}
+ void CenterOnItemsBoundingRect();
+
signals:
void NodesSelected(const QVector& nodes);
@@ -137,12 +135,6 @@ private:
void ZoomFromKeyboard(double multiplier);
- bool DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge);
- void UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges);
- void UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges = Node::OutputConnections());
- void RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context);
- void RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing);
-
QPointF GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const;
Menu *CreateAddMenu(Menu *parent);
@@ -151,8 +143,6 @@ private:
void PositionNewEdge(const QPoint &pos);
- NodeViewItem *UpdateNodeItem(Node *node, bool ignore_own_context = false);
-
void PasteNodesInternal(const QVector &duplicate_nodes = QVector());
class NodeViewAttachNodesToCursor : public UndoCommand
@@ -176,8 +166,6 @@ private:
NodeViewMiniMap *minimap_;
- NodeGraph* graph_;
-
struct AttachedItem {
NodeViewItem* item;
QPointF original_pos;
@@ -227,21 +215,7 @@ private:
QVector selected_nodes_;
- enum FilterMode {
- kFilterShowAll,
- kFilterShowSelective
- };
-
- struct Position {
- Node *node;
- QPointF original_item_pos;
- };
-
- QMap positions_;
-
- FilterMode filter_mode_;
-
- QVector filter_nodes_;
+ QVector contexts_;
QVector last_set_filter_nodes_;
QMap context_offsets_;
@@ -249,7 +223,7 @@ private:
bool create_edge_already_exists_;
- bool queue_reposition_contexts_;
+ bool first_show_;
static const double kMinimumScale;
@@ -274,36 +248,19 @@ private slots:
*/
void ContextMenuSetDirection(QAction* action);
- /**
- * @brief Receiver for the user changing the filter
- */
- void ContextMenuFilterChanged(QAction* action);
-
/**
* @brief Opens the selected node in a Viewer
*/
void OpenSelectedNodeInViewer();
- //void AddNode(Node *node);
- void RemoveNode(Node *node);
- void AddEdge(Node *output, const NodeInput& input);
- void RemoveEdge(Node *output, const NodeInput& input);
-
- void AddNodePosition(Node *node, Node *relative);
- void RemoveNodePosition(Node *node, Node *relative);
-
void UpdateSceneBoundingRect();
- void CenterOnItemsBoundingRect();
-
void RepositionMiniMap();
void UpdateViewportOnMiniMap();
void MoveToScenePoint(const QPointF &pos);
- void RepositionContexts();
-
void GroupNodes();
void UngroupNodes();
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
index db22be143..1b52624a6 100644
--- a/app/widget/nodeview/nodeviewcontext.cpp
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -19,37 +19,29 @@ namespace olive {
#define super QGraphicsRectItem
-NodeViewContext::NodeViewContext(QGraphicsItem *item) :
- super(item)
+NodeViewContext::NodeViewContext(Node *context, QGraphicsItem *item) :
+ super(item),
+ context_(context)
{
- // Set default label text
- SetContext(nullptr);
-}
-
-void NodeViewContext::SetContext(Node *node)
-{
- context_ = 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()),
- Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()),
- Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay()));
- } else {
- lbl_ = node->GetLabelAndName();
- }
-
- Color c = node->color();
- setPen(QPen(c.toQColor(), 2));
-
- c.set_alpha(0.5f);
- setBrush(c.toQColor());
+ if (Block *block = dynamic_cast(context_)) {
+ 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()),
+ Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()),
+ Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay()));
} else {
- lbl_ = QCoreApplication::translate("NodeViewContext", "(None)");
+ lbl_ = context_->GetLabelAndName();
}
+
+ const Node::PositionMap &map = context_->GetContextPositions();
+ for (auto it=map.cbegin(); it!=map.cend(); it++) {
+ AddChild(it.key());
+ }
+
+ connect(context_, &Node::NodeAddedToContext, this, &NodeViewContext::AddChild, Qt::DirectConnection);
+ connect(context_, &Node::NodePositionInContextChanged, this, &NodeViewContext::SetChildPosition, Qt::DirectConnection);
+ connect(context_, &Node::NodeRemovedFromContext, this, &NodeViewContext::RemoveChild, Qt::DirectConnection);
}
void NodeViewContext::AddChild(Node *node)
@@ -59,33 +51,73 @@ void NodeViewContext::AddChild(Node *node)
}
NodeViewItem *item = new NodeViewItem(this);
- item->SetNode(node);
- item->SetNodePosition(context_->parent()->GetNodesForContext(context_).value(node));
+ item->SetNode(node, context_);
+ item->SetNodePosition(context_->GetNodePositionInContext(node));
item->SetFlowDirection(flow_dir_);
+ connect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
+ connect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
+
+ item_map_.insert(node, item);
+
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);
- }
+ if (!it->second.IsHidden()) {
+ if (NodeViewItem *other_item = item_map_.value(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);
- }
+ if (!it->first.IsHidden()) {
+ if (NodeViewItem *other_item = item_map_.value(it->second)) {
+ AddEdgeInternal(it->second, it->first, other_item, item);
}
}
}
+
+ UpdateRect();
+}
+
+void NodeViewContext::SetChildPosition(Node *node, const QPointF &pos)
+{
+ item_map_.value(node)->SetNodePosition(pos);
+}
+
+void NodeViewContext::RemoveChild(Node *node)
+{
+ disconnect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
+ disconnect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
+
+ delete item_map_.take(node);
+}
+
+void NodeViewContext::ChildInputConnected(Node *output, const NodeInput &input)
+{
+ // Add edge
+ if (!input.IsHidden()) {
+ if (NodeViewItem* output_item = item_map_.value(output)) {
+ AddEdgeInternal(output, input, output_item, item_map_.value(input.node()));
+ }
+ }
+}
+
+bool NodeViewContext::ChildInputDisconnected(Node *output, const NodeInput &input)
+{
+ // Remove edge
+ for (int i=0; ioutput() == output && edges_.at(i)->input() == input) {
+ delete edges_.at(i);
+ edges_.removeAt(i);
+ return true;
+ }
+ }
+
+ return false;
}
qreal GetTextOffset(const QFontMetricsF &fm)
@@ -105,23 +137,19 @@ void NodeViewContext::UpdateRect()
rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad);
setRect(rect);
- last_titlebar_height_ = rect.y() + (cbr.y() - rect.y());
+ last_titlebar_height_ = rect.y() + (cbr.y() - rect.y()) - pad;
}
void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
flow_dir_ = dir;
- foreach (auto child, childItems()) {
- if (NodeViewItem *item = dynamic_cast(child)) {
- item->SetFlowDirection(dir);
- }
+ foreach (NodeViewItem *item, item_map_) {
+ item->SetFlowDirection(dir);
}
- foreach (auto child, childItems()) {
- if (NodeViewEdge *edge = dynamic_cast(child)) {
- edge->SetFlowDirection(dir);
- }
+ foreach (NodeViewEdge *edge, edges_) {
+ edge->SetFlowDirection(dir);
}
}
@@ -129,29 +157,40 @@ 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);
- }
+ foreach (NodeViewEdge *edge, edges_) {
+ edge->SetCurved(e);
}
}
void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
- QPen p = pen();
-
+ // Set pen and brush
+ Color color = context_->color();
+ QColor c = color.toQColor();
+ QPen pen(c, 2);
if (option->state & QStyle::State_Selected) {
- p.setStyle(Qt::DotLine);
+ pen.setStyle(Qt::DotLine);
}
+ painter->setPen(pen);
- painter->setPen(p);
- painter->setBrush(brush());
+ QColor bg = c;
+ bg.setAlpha(128);
+ painter->setBrush(bg);
+ // Draw semi-transparent rect for whole item
int rounded = painter->fontMetrics().height();
painter->drawRoundedRect(rect(), rounded, rounded);
- painter->setPen(widget->palette().text().color());
+ // Draw solid background for titlebar
+ QRectF titlebar_rect = rect();
+ titlebar_rect.setHeight(last_titlebar_height_ - rect().top());
+ painter->setClipRect(titlebar_rect);
+ painter->setBrush(c);
+ painter->drawRoundedRect(rect(), rounded, rounded);
+ painter->setClipping(false);
+
+ // Draw titlebar text
+ painter->setPen(ColorCoding::GetUISelectorColor(color));
int offset = GetTextOffset(painter->fontMetrics());
@@ -182,8 +221,7 @@ NodeViewEdge* NodeViewContext::AddEdgeInternal(Node *output, const NodeInput& in
edge_ui->SetFlowDirection(flow_dir_);
edge_ui->SetCurved(curved_edges_);
- from->AddEdge(edge_ui);
- to->AddEdge(edge_ui);
+ edges_.append(edge_ui);
return edge_ui;
}
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
index cf35b6fd2..4ef21f68f 100644
--- a/app/widget/nodeview/nodeviewcontext.h
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -10,14 +10,11 @@
namespace olive {
-class NodeViewContext : public QGraphicsRectItem
+class NodeViewContext : public QObject, public QGraphicsRectItem
{
+ Q_OBJECT
public:
- NodeViewContext(QGraphicsItem *item = nullptr);
-
- void SetContext(Node *node);
-
- void AddChild(Node *node);
+ NodeViewContext(Node *context, QGraphicsItem *item = nullptr);
void UpdateRect();
@@ -27,6 +24,17 @@ public:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
+public slots:
+ void AddChild(Node *node);
+
+ void SetChildPosition(Node *node, const QPointF &pos);
+
+ void RemoveChild(Node *node);
+
+ void ChildInputConnected(Node *output, const NodeInput& input);
+
+ bool ChildInputDisconnected(Node *output, const NodeInput& input);
+
protected:
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
@@ -45,6 +53,10 @@ private:
int last_titlebar_height_;
+ QMap item_map_;
+
+ QVector edges_;
+
};
}
diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp
index 977b88cbd..caf629007 100644
--- a/app/widget/nodeview/nodeviewedge.cpp
+++ b/app/widget/nodeview/nodeviewedge.cpp
@@ -46,6 +46,9 @@ NodeViewEdge::NodeViewEdge(Node *output, const NodeInput &input,
{
Init();
SetConnected(true);
+
+ from_item_->AddEdge(this);
+ to_item_->AddEdge(this);
}
NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
@@ -56,6 +59,17 @@ NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
Init();
}
+NodeViewEdge::~NodeViewEdge()
+{
+ if (from_item_) {
+ from_item_->RemoveEdge(this);
+ }
+
+ if (to_item_) {
+ to_item_->RemoveEdge(this);
+ }
+}
+
void NodeViewEdge::Adjust()
{
// Draw a line between the two
diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h
index de8d10720..31a56664e 100644
--- a/app/widget/nodeview/nodeviewedge.h
+++ b/app/widget/nodeview/nodeviewedge.h
@@ -45,6 +45,8 @@ public:
NodeViewEdge(QGraphicsItem* parent = nullptr);
+ virtual ~NodeViewEdge() override;
+
Node *output() const
{
return output_;
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index b3e4ee4e9..1c73f8ddd 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -42,6 +42,7 @@ namespace olive {
NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
QGraphicsRectItem(parent),
node_(nullptr),
+ context_(nullptr),
expanded_(false),
hide_titlebar_(false),
highlighted_index_(-1),
@@ -207,7 +208,7 @@ int NodeViewItem::GetIndexAt(QPointF pt) const
return -1;
}
-void NodeViewItem::SetNode(Node *n)
+void NodeViewItem::SetNode(Node *n, Node *context)
{
if (node_) {
disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
@@ -215,6 +216,7 @@ void NodeViewItem::SetNode(Node *n)
}
node_ = n;
+ context_ = context;
node_inputs_.clear();
input_connectors_.clear();
@@ -223,7 +225,7 @@ void NodeViewItem::SetNode(Node *n)
node_->Retranslate();
foreach (const QString& input, node_->inputs()) {
- if (node_->IsInputConnectable(input)) {
+ if (node_->IsInputConnectable(input) && !node_->IsInputHidden(input)) {
node_inputs_.append(input);
}
}
@@ -327,9 +329,11 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
int icon_size = painter->fontMetrics().height()/2;
+ bool draw_arrow = !node_inputs_.isEmpty();
+
if (node_label.isEmpty()) {
// Draw shortname only
- DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, true);
+ DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, draw_arrow);
} else {
int text_pad = DefaultTextPadding()/2;
QRectF safe_label_bounds = title_bar_rect_.adjusted(text_pad, text_pad, -text_pad, -text_pad);
@@ -337,7 +341,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
qreal font_sz = f.pointSizeF();
f.setPointSizeF(font_sz * 0.8);
painter->setFont(f);
- DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, true);
+ DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, draw_arrow);
f.setPointSizeF(font_sz * 0.6);
painter->setFont(f);
DrawNodeTitle(painter, node_shortname, safe_label_bounds, Qt::AlignBottom, icon_size, false);
diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h
index 0f11574ed..b92f531c7 100644
--- a/app/widget/nodeview/nodeviewitem.h
+++ b/app/widget/nodeview/nodeviewitem.h
@@ -53,7 +53,7 @@ public:
/**
* @brief Set the Node to correspond to this widget
*/
- void SetNode(Node* n);
+ void SetNode(Node* n, Node *context);
/**
* @brief Get currently attached node
@@ -174,6 +174,8 @@ private:
*/
Node* node_;
+ Node *context_;
+
/**
* @brief Cached list of node inputs
*/
diff --git a/app/widget/nodeview/nodeviewminimap.cpp b/app/widget/nodeview/nodeviewminimap.cpp
index d1e20791c..8dc99c914 100644
--- a/app/widget/nodeview/nodeviewminimap.cpp
+++ b/app/widget/nodeview/nodeviewminimap.cpp
@@ -38,6 +38,7 @@ NodeViewMiniMap::NodeViewMiniMap(NodeViewScene *scene, QWidget *parent) :
setViewportUpdateMode(FullViewportUpdate);
setFrameShape(QFrame::Panel);
setFrameShadow(QFrame::Plain);
+ setMouseTracking(true);
QMetaObject::invokeMethod(this, &NodeViewMiniMap::SetDefaultSize, Qt::QueuedConnection);
@@ -87,7 +88,7 @@ void NodeViewMiniMap::resizeEvent(QResizeEvent *event)
void NodeViewMiniMap::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
- if (event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_) {
+ if (MouseInsideResizeTriangle(event)) {
// Resizing!
resizing_ = true;
resize_anchor_ = QCursor::pos();
@@ -107,6 +108,8 @@ void NodeViewMiniMap::mouseMoveEvent(QMouseEvent *event)
} else {
EmitMoveSignal(event);
}
+ } else {
+ setCursor(MouseInsideResizeTriangle(event) ? Qt::SizeFDiagCursor : Qt::ArrowCursor);
}
}
@@ -135,6 +138,11 @@ void NodeViewMiniMap::SetDefaultSize()
}
}
+bool NodeViewMiniMap::MouseInsideResizeTriangle(QMouseEvent *event)
+{
+ return event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_;
+}
+
void NodeViewMiniMap::EmitMoveSignal(QMouseEvent *event)
{
emit MoveToScenePoint(mapToScene(event->pos()));
diff --git a/app/widget/nodeview/nodeviewminimap.h b/app/widget/nodeview/nodeviewminimap.h
index a63db1993..e155b54f2 100644
--- a/app/widget/nodeview/nodeviewminimap.h
+++ b/app/widget/nodeview/nodeviewminimap.h
@@ -57,6 +57,8 @@ private slots:
void SetDefaultSize();
private:
+ bool MouseInsideResizeTriangle(QMouseEvent *event);
+
void EmitMoveSignal(QMouseEvent *event);
int resize_triangle_sz_;
diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp
index feb2598b3..2e04a2ae6 100644
--- a/app/widget/nodeview/nodeviewscene.cpp
+++ b/app/widget/nodeview/nodeviewscene.cpp
@@ -143,45 +143,25 @@ QVector NodeViewScene::GetSelectedEdges() const
return edges;
}
-NodeViewEdge* NodeViewScene::AddEdge(Node *output, const NodeInput &input)
-{
- NodeViewEdge *edge = EdgeToUIObject(output, input);
-
- if (!edge) {
- edge = AddEdgeInternal(output, input, NodeToUIObject(output), NodeToUIObject(input.node()));
- }
-
- return edge;
-}
-
-void NodeViewScene::RemoveEdge(Node *output, const NodeInput &input)
-{
- NodeViewEdge* edge = EdgeToUIObject(output, input);
- if (edge) {
- edge->from_item()->RemoveEdge(edge);
- edge->to_item()->RemoveEdge(edge);
- edges_.removeOne(edge);
- delete edge;
- }
-}
-
NodeViewContext *NodeViewScene::AddContext(Node *node)
{
NodeViewContext *context_item = context_map_.value(node);
if (!context_item) {
- context_item = new NodeViewContext();
- context_item->SetContext(node);
- context_item->setPos(0, 0);
+ context_item = new NodeViewContext(node);
+
context_item->SetFlowDirection(GetFlowDirection());
context_item->SetCurvedEdges(GetEdgesAreCurved());
- addItem(context_item);
- const NodeGraph::PositionMap &map = node->parent()->GetNodesForContext(node);
- for (auto it=map.cbegin(); it!=map.cend(); it++) {
- context_item->AddChild(it.key());
+ QPointF pos(0, 0);
+ QRectF item_rect = context_item->rect();
+ while (!items(item_rect).isEmpty()) {
+ pos.setY(pos.y() + item_rect.height());
+ item_rect = context_item->rect().translated(pos);
}
- context_item->UpdateRect();
+ context_item->setPos(pos);
+
+ addItem(context_item);
context_map_.insert(node, context_item);
}
@@ -209,22 +189,6 @@ int NodeViewScene::DetermineWeight(Node *n)
return qMax(1, weight);
}
-NodeViewEdge* NodeViewScene::AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to)
-{
- NodeViewEdge* edge_ui = new NodeViewEdge(output, input, from, to);
-
- edge_ui->SetFlowDirection(direction_);
- edge_ui->SetCurved(curved_edges_);
-
- from->AddEdge(edge_ui);
- to->AddEdge(edge_ui);
-
- addItem(edge_ui);
- edges_.append(edge_ui);
-
- return edge_ui;
-}
-
Qt::Orientation NodeViewScene::GetFlowOrientation() const
{
return NodeViewCommon::GetFlowOrientation(direction_);
@@ -240,8 +204,8 @@ void NodeViewScene::SetEdgesAreCurved(bool curved)
if (curved_edges_ != curved) {
curved_edges_ = curved;
- foreach (NodeViewEdge* e, edges_) {
- e->SetCurved(curved_edges_);
+ foreach (NodeViewContext *ctx, context_map_) {
+ ctx->SetCurvedEdges(curved_edges_);
}
}
}
diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h
index f37ebbdcd..db49aca89 100644
--- a/app/widget/nodeview/nodeviewscene.h
+++ b/app/widget/nodeview/nodeviewscene.h
@@ -81,9 +81,6 @@ public:
}
public slots:
- NodeViewEdge *AddEdge(Node *output, const NodeInput& input);
- void RemoveEdge(Node *output, const NodeInput& input);
-
NodeViewContext *AddContext(Node *node);
void RemoveContext(Node *node);
@@ -95,8 +92,6 @@ public slots:
private:
static int DetermineWeight(Node* n);
- NodeViewEdge* AddEdgeInternal(Node *output, const NodeInput &input, NodeViewItem* from, NodeViewItem* to);
-
QHash context_map_;
QHash item_map_;
diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp
index 07343ccd3..a9c9d3615 100644
--- a/app/widget/timelinewidget/tool/add.cpp
+++ b/app/widget/timelinewidget/tool/add.cpp
@@ -116,7 +116,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
NodeGraph* graph = static_cast(parent()->GetConnectedNode()->parent());
command->add_child(new NodeAddCommand(graph, clip));
- command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false));
+ command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0)));
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
track.index(),
clip,
@@ -155,10 +155,10 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
}
if (node_to_add) {
- QPointF extra_node_offset(-1, 0);
+ QPointF extra_node_offset(kDefaultDistanceFromOutput, 0);
command->add_child(new NodeAddCommand(graph, node_to_add));
command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn)));
- command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset, false));
+ command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset));
}
Core::instance()->undo_stack()->push(command);
diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp
index 9ad1a6a74..f9ab4b6f8 100644
--- a/app/widget/timelinewidget/tool/import.cpp
+++ b/app/widget/timelinewidget/tool/import.cpp
@@ -355,7 +355,7 @@ void ImportTool::DropGhosts(bool insert)
command->add_child(new NodeAddCommand(dst_graph, new_sequence));
command->add_child(new FolderAddChild(Core::instance()->GetSelectedFolderInActiveProject(), new_sequence));
- command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false));
+ command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0)));
new_sequence->add_default_nodes(command);
FootageToGhosts(0, dragged_footage_, new_sequence->GetVideoParams().time_base(), 0);
@@ -394,10 +394,14 @@ void ImportTool::DropGhosts(bool insert)
command->add_child(new NodeAddCommand(dst_graph, clip));
// Position clip in its own context
- command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false));
+ command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0)));
+
+ int dep_pos = kDefaultDistanceFromOutput;
// Position footage in its context
- command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(-3, 0), false));
+ command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(dep_pos, 0)));
+
+ dep_pos++;
switch (Track::Reference::TypeFromString(footage_stream.output)) {
case Track::kVideo:
@@ -409,7 +413,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(-2, 0), false));
+ command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(dep_pos, 0)));
break;
}
case Track::kAudio:
@@ -421,7 +425,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(-2, 0), false));
+ command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(dep_pos, 0)));
break;
}
default:
diff --git a/app/widget/timelinewidget/tool/tool.cpp b/app/widget/timelinewidget/tool/tool.cpp
index 752409b78..2612b9697 100644
--- a/app/widget/timelinewidget/tool/tool.cpp
+++ b/app/widget/timelinewidget/tool/tool.cpp
@@ -24,6 +24,8 @@
namespace olive {
+const int TimelineTool::kDefaultDistanceFromOutput = -4;
+
TimelineTool::TimelineTool(TimelineWidget *parent) :
dragging_(false),
parent_(parent)
diff --git a/app/widget/timelinewidget/tool/tool.h b/app/widget/timelinewidget/tool/tool.h
index d229e1ad3..c627f542e 100644
--- a/app/widget/timelinewidget/tool/tool.h
+++ b/app/widget/timelinewidget/tool/tool.h
@@ -84,6 +84,8 @@ protected:
TimelineCoordinate drag_start_;
+ static const int kDefaultDistanceFromOutput;
+
private:
TimelineWidget* parent_;
diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp
index f1a1f4fdd..594659ccb 100644
--- a/app/widget/timelinewidget/tool/transition.cpp
+++ b/app/widget/timelinewidget/tool/transition.cpp
@@ -113,7 +113,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
command->add_child(new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()),
transition));
- command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0), false));
+ command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0)));
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
track.index(),
@@ -138,8 +138,8 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
command->add_child(new NodeEdgeAddCommand(in_block,
NodeInput(transition, TransitionBlock::kInBlockInput)));
- command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5), false));
- command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5), false));
+ command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5)));
+ command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5)));
} else {
Block* block_to_transition = Node::ValueToPtr(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock));
QString transition_input_to_connect;
@@ -154,7 +154,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
command->add_child(new NodeEdgeAddCommand(block_to_transition,
NodeInput(transition, transition_input_to_connect)));
- command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0), false));
+ command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0)));
}
Core::instance()->undo_stack()->push(command);
diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.cpp b/app/widget/timelinewidget/undo/timelineundogeneral.cpp
index 63958f250..9c8bbae14 100644
--- a/app/widget/timelinewidget/undo/timelineundogeneral.cpp
+++ b/app/widget/timelinewidget/undo/timelineundogeneral.cpp
@@ -73,131 +73,121 @@ void BlockSetMediaInCommand::undo()
//
// TimelineAddTrackCommand
//
-TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks)
+TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks) :
+ timeline_(timeline),
+ merge_(nullptr),
+ position_command_(nullptr)
{
- timeline_ = timeline;
- position_command_ = nullptr;
-
+ // Create new track
track_ = new Track();
track_->setParent(&memory_manager_);
- if (timeline->GetTrackCount() > 0 && automerge_tracks) {
- if (timeline_->type() == Track::kVideo) {
- merge_ = new MergeNode();
- base_ = NodeInput(merge_, MergeNode::kBaseIn);
- blend_ = NodeInput(merge_, MergeNode::kBlendIn);
- } else if (timeline_->type() == Track::kAudio) {
- merge_ = new MathNode();
- base_ = NodeInput(merge_, MathNode::kParamAIn);
- blend_ = NodeInput(merge_, MathNode::kParamBIn);
- } else {
- merge_ = nullptr;
- }
- } else {
- merge_ = nullptr;
+ // Determine what input to connect it to
+ QString relevant_input;
+
+ if (timeline_->type() == Track::kVideo) {
+ relevant_input = Sequence::kTextureInput;
+ } else if (timeline_->type() == Track::kAudio) {
+ relevant_input = Sequence::kSamplesInput;
}
- if (merge_) {
- merge_->setParent(&memory_manager_);
+ // If we have an input to connect to, set it as our `direct` connection
+ if (!relevant_input.isEmpty()) {
+ direct_ = NodeInput(timeline_->parent(), relevant_input);
+
+ // If we're automerging and something is already connected, determine if/how to merge it
+ if (automerge_tracks && direct_.IsConnected()) {
+ if (timeline_->type() == Track::kVideo) {
+ // Use merge for video
+ merge_ = new MergeNode();
+ base_ = NodeInput(merge_, MergeNode::kBaseIn);
+ blend_ = NodeInput(merge_, MergeNode::kBlendIn);
+ } else if (timeline_->type() == Track::kAudio) {
+ // Use math (add) for audio
+ merge_ = new MathNode();
+ base_ = NodeInput(merge_, MathNode::kParamAIn);
+ blend_ = NodeInput(merge_, MathNode::kParamBIn);
+ }
+
+ if (merge_) {
+ // If we got created a merge node, ensure it's parented
+ merge_->setParent(&memory_manager_);
+ }
+ }
}
}
void TimelineAddTrackCommand::redo()
{
- // Add track
+ // Get sequence
+ Sequence* sequence = timeline_->parent();
+
+ // Add track to sequence
track_->setParent(timeline_->GetParentGraph());
timeline_->ArrayAppend();
Node::ConnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1));
+ qreal position_factor = 0.5;
+ if (timeline_->type() == Track::kVideo) {
+ position_factor = -position_factor;
+ }
+ bool create_pos_command = (!position_command_ && (timeline_->type() == Track::kVideo || timeline_->type() == Track::kAudio));
+ if (create_pos_command) {
+ position_command_ = new MultiUndoCommand();
+ }
+
// Add merge if applicable
- Track* last_track = nullptr;
if (merge_) {
+ // Determine what was previously connected
+ Node *previous_connection = direct_.GetConnectedOutput();
+
+ // Add merge to graph
merge_->setParent(timeline_->GetParentGraph());
- last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2);
-
- // Whatever this track used to be connected to, connect the merge instead
- const Node::OutputConnections edges = last_track->output_connections();
- for (const Node::OutputConnection& ic : edges) {
- const NodeInput& i = ic.second;
-
- // Ignore the track input, but funnel everything else through our merge
- if (i.node() != timeline_->parent() || i.input() != timeline_->track_input()) {
- Node::DisconnectEdge(last_track, i);
- Node::ConnectEdge(merge_, i);
- }
- }
-
- // Connect this as the "blend" track
+ // Connect merge between what used to be here
+ Node::DisconnectEdge(previous_connection, direct_);
+ Node::ConnectEdge(merge_, direct_);
+ Node::ConnectEdge(previous_connection, base_);
Node::ConnectEdge(track_, blend_);
- Node::ConnectEdge(last_track, base_);
- } else if (timeline_->GetTrackCount() == 1) {
- // If this was the first track we added,
- QString relevant_input;
- if (timeline_->type() == Track::kVideo) {
- relevant_input = ViewerOutput::kTextureInput;
- } else if (timeline_->type() == Track::kAudio) {
- relevant_input = ViewerOutput::kSamplesInput;
+ if (create_pos_command) {
+ position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, -position_factor)));
+ position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence)));
+ position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor * timeline_->GetTrackCount()), true));
}
+ } else if (direct_.IsValid() && !direct_.IsConnected()) {
+ // If no merge, we have a direct connection, and nothing else is connected, connect this
+ Node::ConnectEdge(track_, direct_);
- if (!relevant_input.isEmpty() && !timeline_->parent()->IsInputConnected(relevant_input)) {
- direct_ = NodeInput(timeline_->parent(), relevant_input);
-
- Node::ConnectEdge(track_, direct_);
- } else {
- direct_ = NodeInput();
+ if (create_pos_command) {
+ // Just position directly next to the context node
+ position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor)));
}
}
- // Position track in context
- if (!position_command_) {
- int track_count = timeline_->parent()->GetTracks().size();
- position_command_ = new MultiUndoCommand();
-
- // Position either the merge or the track as an "element"
- Node *node_to_position = merge_ ? merge_ : track_;
- double node_index = track_count - 1;
- if (merge_) {
- node_index -= 1;
- position_command_->add_child(new NodeRemovePositionFromContextCommand(last_track, timeline_->parent()));
- }
-
- position_command_->add_child(new NodeSetPositionAsChildCommand(node_to_position, timeline_->parent(), timeline_->parent(), node_index, track_count, true));
-
- // If we positioned a merge, position the tracks as children of the merge
- if (merge_) {
- // `last_track` should be non-null if `merge_` is non-null
- position_command_->add_child(new NodeSetPositionAsChildCommand(last_track, merge_, timeline_->parent(), 0, 2, true));
- position_command_->add_child(new NodeSetPositionAsChildCommand(track_, merge_, timeline_->parent(), 1, 2, true));
- }
+ // Run position command if we created one
+ if (position_command_) {
+ position_command_->redo_now();
}
- position_command_->redo_now();
}
void TimelineAddTrackCommand::undo()
{
- position_command_->undo_now();
+ if (position_command_) {
+ position_command_->undo_now();
+ }
// Remove merge if applicable
if (merge_) {
- // Assume whatever this merge is connected to USED to be connected to the last track
- Track* last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2);
+ Node *previous_connection = base_.GetConnectedOutput();
Node::DisconnectEdge(track_, blend_);
- Node::DisconnectEdge(last_track, base_);
-
- // Make copy of edges since the node's internal array will change as we disconnect things
- const Node::OutputConnections edges = merge_->output_connections();
- for (const Node::OutputConnection& ic : edges) {
- const NodeInput& i = ic.second;
-
- Node::DisconnectEdge(merge_, i);
- Node::ConnectEdge(last_track, i);
- }
+ Node::DisconnectEdge(previous_connection, base_);
+ Node::DisconnectEdge(merge_, direct_);
+ Node::ConnectEdge(previous_connection, direct_);
merge_->setParent(&memory_manager_);
- } else if (direct_.IsValid()) {
+ } else if (direct_.IsValid() && direct_.GetConnectedOutput() == track_) {
Node::DisconnectEdge(track_, direct_);
}
@@ -496,11 +486,6 @@ void TrackReplaceBlockWithGapCommand::redo()
our_gap_->setParent(track_->parent());
track_->ReplaceBlock(block_, our_gap_);
-
- if (!position_command_) {
- position_command_ = new NodeSetPositionAsChildCommand(our_gap_, track_, track_, our_gap_->index(), track_->Blocks().size(), true);
- }
- position_command_->redo_now();
}
track_->EndOperation();
@@ -533,8 +518,6 @@ void TrackReplaceBlockWithGapCommand::undo()
track_->ReplaceBlock(our_gap_, block_);
our_gap_->setParent(&memory_manager_);
- position_command_->undo_now();
-
} else {
// If we're here, assume that we extended an existing gap
diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.h b/app/widget/timelinewidget/undo/timelineundogeneral.h
index 423f4da84..490d9b082 100644
--- a/app/widget/timelinewidget/undo/timelineundogeneral.h
+++ b/app/widget/timelinewidget/undo/timelineundogeneral.h
@@ -203,16 +203,10 @@ public:
existing_gap_(nullptr),
existing_merged_gap_(nullptr),
our_gap_(nullptr),
- handle_transitions_(handle_transitions),
- position_command_(nullptr)
+ handle_transitions_(handle_transitions)
{
}
- virtual ~TrackReplaceBlockWithGapCommand() override
- {
- delete position_command_;
- }
-
virtual Project* GetRelevantProject() const override
{
return block_->project();
@@ -236,8 +230,6 @@ private:
bool handle_transitions_;
- NodeSetPositionAsChildCommand* position_command_;
-
QObject memory_manager_;
QVector transition_remove_commands_;
diff --git a/app/widget/timelinewidget/undo/timelineundopointer.cpp b/app/widget/timelinewidget/undo/timelineundopointer.cpp
index 4f5c448b6..0f6501b19 100644
--- a/app/widget/timelinewidget/undo/timelineundopointer.cpp
+++ b/app/widget/timelinewidget/undo/timelineundopointer.cpp
@@ -324,7 +324,6 @@ TrackPlaceBlockCommand::~TrackPlaceBlockCommand()
{
delete ripple_remove_command_;
qDeleteAll(add_track_commands_);
- qDeleteAll(position_commands_);
}
void TrackPlaceBlockCommand::redo()
@@ -367,14 +366,6 @@ void TrackPlaceBlockCommand::redo()
}
track->AppendBlock(insert_);
-
- if (position_commands_.isEmpty()) {
- // Create position commands for insert and gap if necessary
- if (gap_) {
- position_commands_.append(new NodeSetPositionAsChildCommand(gap_, track, track, gap_->index(), track->Blocks().size(), true));
- }
- position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true));
- }
} else {
// Place the Block at this point
if (!ripple_remove_command_) {
@@ -384,10 +375,6 @@ void TrackPlaceBlockCommand::redo()
ripple_remove_command_->redo_now();
track->InsertBlockAfter(insert_, ripple_remove_command_->GetInsertionIndex());
-
- if (position_commands_.isEmpty()) {
- position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true));
- }
}
track->EndOperation();
@@ -397,18 +384,10 @@ void TrackPlaceBlockCommand::redo()
foreach (const TimeRange &r, ranges_to_invalidate) {
track->Node::InvalidateCache(r, Track::kBlockInput);
}
-
- for (int i=0; iredo_now();
- }
}
void TrackPlaceBlockCommand::undo()
{
- for (int i=position_commands_.size()-1; i>=0; i--) {
- position_commands_.at(i)->undo_now();
- }
-
Track* t = timeline_->GetTrackAt(track_index_);
TimeRange insert_range(insert_->in(), insert_->out());
diff --git a/app/widget/timelinewidget/undo/timelineundopointer.h b/app/widget/timelinewidget/undo/timelineundopointer.h
index fc7cf6566..4483d81d2 100644
--- a/app/widget/timelinewidget/undo/timelineundopointer.h
+++ b/app/widget/timelinewidget/undo/timelineundopointer.h
@@ -198,7 +198,6 @@ private:
QVector add_track_commands_;
QObject memory_manager_;
TrackRippleRemoveAreaCommand* ripple_remove_command_;
- QVector position_commands_;
};
diff --git a/app/widget/timelinewidget/undo/timelineundosplit.cpp b/app/widget/timelinewidget/undo/timelineundosplit.cpp
index 05c3b2707..06cdd1006 100644
--- a/app/widget/timelinewidget/undo/timelineundosplit.cpp
+++ b/app/widget/timelinewidget/undo/timelineundosplit.cpp
@@ -61,12 +61,6 @@ void BlockSplitCommand::redo()
// Insert new block
track->InsertBlockAfter(new_block(), block_);
- // Position the block
- if (!position_command_) {
- position_command_ = new NodeSetPositionAsChildCommand(new_block(), track, track, new_block()->index(), track->Blocks().size(), true);
- }
- position_command_->redo_now();
-
// If the block had an out transition, we move it to the new block
moved_transition_ = NodeInput();
@@ -96,8 +90,6 @@ void BlockSplitCommand::undo()
Node::ConnectEdge(block_, moved_transition_);
}
- position_command_->undo_now();
-
block_->set_length_and_media_out(old_length_);
track->RippleRemoveBlock(new_block());
diff --git a/app/widget/timelinewidget/undo/timelineundosplit.h b/app/widget/timelinewidget/undo/timelineundosplit.h
index 82b57ebca..6984377f8 100644
--- a/app/widget/timelinewidget/undo/timelineundosplit.h
+++ b/app/widget/timelinewidget/undo/timelineundosplit.h
@@ -31,15 +31,13 @@ public:
block_(block),
new_block_(nullptr),
point_(point),
- reconnect_tree_command_(nullptr),
- position_command_(nullptr)
+ reconnect_tree_command_(nullptr)
{
}
virtual ~BlockSplitCommand() override
{
delete reconnect_tree_command_;
- delete position_command_;
}
virtual Project* GetRelevantProject() const override
@@ -70,8 +68,6 @@ private:
NodeInput moved_transition_;
- NodeSetPositionAsChildCommand* position_command_;
-
};
class BlockSplitPreservingLinksCommand : public UndoCommand {
diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp
index 8f1ace9ef..47c23c3cb 100644
--- a/app/window/mainwindow/mainwindow.cpp
+++ b/app/window/mainwindow/mainwindow.cpp
@@ -378,9 +378,7 @@ void MainWindow::ProjectClose(Project *p)
}
// Close project from NodeView
- if (node_panel_->GetGraph() == p) {
- node_panel_->ClearGraph();
- }
+ node_panel_->CloseContextsBelongingToProject(p);
}
void MainWindow::SetApplicationProgressStatus(ProgressStatus status)
@@ -731,11 +729,7 @@ void MainWindow::UpdateNodePanelContextFromTimelinePanel(TimelinePanel *panel)
context.append(viewer);
}
- QVector old_contexts = node_panel_->GetCurrentContexts();
- node_panel_->SetGraph(viewer ? viewer->parent() : nullptr, context);
- if (viewer && context != old_contexts) {
- node_panel_->SelectAll();
- }
+ node_panel_->SetContexts(context);
}
void MainWindow::FocusedPanelChanged(PanelWidget *panel)
@@ -753,10 +747,6 @@ void MainWindow::FocusedPanelChanged(PanelWidget *panel)
} else if (ProjectPanel* project = dynamic_cast(panel)) {
// Signal project panel focus
UpdateTitle();
- if (Project *p = project->project()) {
- node_panel_->SetGraph(p, {p->root()});
- node_panel_->Select({p->color_manager(), p->settings()}, true);
- }
}
}
From a6af473f5322479838cee10898c001aca6a22983 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Wed, 17 Nov 2021 12:09:41 -0800
Subject: [PATCH 07/34] reimplemented node positioning and deleting
---
app/node/graph.cpp | 13 ++++
app/node/graph.h | 2 +
app/task/project/loadotio/loadotio.cpp | 14 ++--
app/widget/nodeview/nodeview.cpp | 52 ++++----------
app/widget/nodeview/nodeview.h | 2 +
app/widget/nodeview/nodeviewcontext.cpp | 34 ++++++++-
app/widget/nodeview/nodeviewcontext.h | 5 ++
app/widget/nodeview/nodeviewitem.cpp | 60 +++++++---------
app/widget/nodeview/nodeviewitem.h | 12 ++--
app/widget/nodeview/nodeviewscene.cpp | 55 +++++---------
app/widget/nodeview/nodeviewscene.h | 11 +--
app/widget/nodeview/nodeviewundo.cpp | 96 +++++++++++++++++++++++++
app/widget/nodeview/nodeviewundo.h | 36 ++++++++++
13 files changed, 255 insertions(+), 137 deletions(-)
diff --git a/app/node/graph.cpp b/app/node/graph.cpp
index f652340fb..bdae43570 100644
--- a/app/node/graph.cpp
+++ b/app/node/graph.cpp
@@ -44,6 +44,19 @@ void NodeGraph::Clear()
}
}
+int NodeGraph::GetNumberOfContextsNodeIsIn(Node *node, bool except_itself) const
+{
+ int count = 0;
+
+ foreach (Node *ctx, node_children_) {
+ if (ctx->ContextContainsNode(node) && (!except_itself || ctx != node)) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
void NodeGraph::childEvent(QChildEvent *event)
{
super::childEvent(event);
diff --git a/app/node/graph.h b/app/node/graph.h
index 21c8f023e..fdf923b56 100644
--- a/app/node/graph.h
+++ b/app/node/graph.h
@@ -63,6 +63,8 @@ public:
return default_nodes_;
}
+ int GetNumberOfContextsNodeIsIn(Node *node, bool except_itself = false) const;
+
signals:
/**
* @brief Signal emitted when a Node is added to the graph
diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp
index bc1983c41..66d2fddf9 100644
--- a/app/task/project/loadotio/loadotio.cpp
+++ b/app/task/project/loadotio/loadotio.cpp
@@ -210,7 +210,7 @@ bool LoadOTIOTask::Run()
block->setParent(sequence->parent());
// Position transition in its own context
- sequence->parent()->SetNodePosition(block, block, QPointF(0, 0));
+ block->SetNodePositionInContext(block, QPointF(0, 0));
}
if (otio_block->schema_name() == "Gap") {
@@ -218,7 +218,7 @@ bool LoadOTIOTask::Run()
block->setParent(sequence->parent());
// Position transition in its own context
- sequence->parent()->SetNodePosition(block, block, QPointF(0, 0));
+ block->SetNodePositionInContext(block, QPointF(0, 0));
}
// Update this after it's used but before any continue statements
@@ -246,7 +246,7 @@ bool LoadOTIOTask::Run()
QFileInfo info(probed_item->filename());
probed_item->SetLabel(info.fileName());
- FolderAddChild add(sequence_footage, probed_item, true);
+ FolderAddChild add(sequence_footage, probed_item);
add.redo_now();
}
@@ -254,10 +254,10 @@ bool LoadOTIOTask::Run()
block->setParent(sequence->parent());
// Position clip in its own context
- sequence->parent()->SetNodePosition(block, block, QPointF(0, 0));
+ block->SetNodePositionInContext(block, QPointF(0, 0));
// Position footage in its context
- sequence->parent()->SetNodePosition(probed_item, block, QPointF(-2, 0));
+ block->SetNodePositionInContext(probed_item, QPointF(-2, 0));
if (track->type() == Track::kVideo) {
@@ -266,14 +266,14 @@ bool LoadOTIOTask::Run()
Node::ConnectEdge(probed_item, NodeInput(transform, TransformDistortNode::kTextureInput));
Node::ConnectEdge(transform, NodeInput(block, ClipBlock::kBufferIn));
- sequence->parent()->SetNodePosition(transform, block, QPointF(-1, 0));
+ block->SetNodePositionInContext(transform, QPointF(-1, 0));
} else {
VolumeNode* volume_node = new VolumeNode();
volume_node->setParent(sequence->parent());
Node::ConnectEdge(probed_item, NodeInput(volume_node, VolumeNode::kSamplesInput));
Node::ConnectEdge(volume_node, NodeInput(block, ClipBlock::kBufferIn));
- sequence->parent()->SetNodePosition(volume_node, block, QPointF(-1, 0));
+ block->SetNodePositionInContext(volume_node, QPointF(-1, 0));
}
}
}
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index 4c8385d9d..3da2c70f1 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -125,43 +125,7 @@ void NodeView::ClearGraph()
void NodeView::DeleteSelected()
{
- MultiUndoCommand* command = new MultiUndoCommand();
-
- {
- // First remove any selected edges
- QVector selected_edges = scene_.GetSelectedEdges();
-
- if (!selected_edges.isEmpty()) {
- Node::OutputConnections removed_connections(selected_edges.size());
-
- for (int i=0; iadd_child(new NodeEdgeRemoveCommand(edge->output(), edge->input()));
- removed_connections[i] = {edge->output(), edge->input()};
- }
- }
- }
-
- {
- // Secondly remove any nodes
- QVector selected_nodes = scene_.GetSelectedNodes();
-
- // Ensure no nodes are "undeletable"
- for (int i=0;iCanBeDeleted()) {
- selected_nodes.removeAt(i);
- i--;
- }
- }
-
- if (!selected_nodes.isEmpty()) {
- for (Node* node : qAsConst(selected_nodes)) {
- command->add_child(new NodeRemoveAndDisconnectCommand(node));
- }
- }
- }
-
- Core::instance()->undo_stack()->pushIfHasChildren(command);
+ scene_.DeleteSelected();
}
void NodeView::SelectAll()
@@ -428,6 +392,11 @@ void NodeView::mousePressEvent(QMouseEvent *event)
}
super::mousePressEvent(event);
+
+ auto selected_items = scene_.GetSelectedItems();
+ foreach (NodeViewItem *i, selected_items) {
+ dragging_nodes_.insert(i, i->GetNodePosition());
+ }
}
void NodeView::mouseMoveEvent(QMouseEvent *event)
@@ -658,6 +627,15 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
DetachItemsFromCursor();
}
+ for (auto it=dragging_nodes_.cbegin(); it!=dragging_nodes_.cend(); it++) {
+ NodeViewItem *i = it.key();
+ QPointF current_pos = i->GetNodePosition();
+ if (it.value() != current_pos) {
+ command->add_child(new NodeSetPositionCommand(i->GetNode(), i->GetContext(), current_pos));
+ }
+ }
+ dragging_nodes_.clear();
+
Core::instance()->undo_stack()->pushIfHasChildren(command);
super::mouseReleaseEvent(event);
diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h
index 8616974f5..c9d7e0e43 100644
--- a/app/widget/nodeview/nodeview.h
+++ b/app/widget/nodeview/nodeview.h
@@ -219,6 +219,8 @@ private:
QVector last_set_filter_nodes_;
QMap context_offsets_;
+ QMap dragging_nodes_;
+
double scale_;
bool create_edge_already_exists_;
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
index 1b52624a6..564e6552a 100644
--- a/app/widget/nodeview/nodeviewcontext.cpp
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -50,9 +50,7 @@ void NodeViewContext::AddChild(Node *node)
return;
}
- NodeViewItem *item = new NodeViewItem(this);
- item->SetNode(node, context_);
- item->SetNodePosition(context_->GetNodePositionInContext(node));
+ NodeViewItem *item = new NodeViewItem(node, context_, this);
item->SetFlowDirection(flow_dir_);
connect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
@@ -162,6 +160,36 @@ void NodeViewContext::SetCurvedEdges(bool e)
}
}
+void NodeViewContext::DeleteSelected(NodeViewDeleteCommand *command)
+{
+ // Delete any selected edges
+ foreach (NodeViewEdge *edge, edges_) {
+ if (edge->isSelected()) {
+ command->AddEdge(edge->output(), edge->input());
+ }
+ }
+
+ // Delete any selected nodes
+ foreach (NodeViewItem *node, item_map_) {
+ if (node->isSelected()) {
+ command->AddNode(node->GetNode(), context_);
+ }
+ }
+}
+
+QVector NodeViewContext::GetSelectedItems() const
+{
+ QVector items;
+
+ for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
+ if (it.value()->isSelected()) {
+ items.append(it.value());
+ }
+ }
+
+ return items;
+}
+
void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// Set pen and brush
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
index 4ef21f68f..8a84751de 100644
--- a/app/widget/nodeview/nodeviewcontext.h
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -7,6 +7,7 @@
#include "node/node.h"
#include "nodeviewcommon.h"
#include "nodeviewedge.h"
+#include "nodeviewundo.h"
namespace olive {
@@ -22,6 +23,10 @@ public:
void SetCurvedEdges(bool e);
+ void DeleteSelected(NodeViewDeleteCommand *command);
+
+ QVector GetSelectedItems() const;
+
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
public slots:
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 1c73f8ddd..009ea45ac 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -39,10 +39,10 @@
namespace olive {
-NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
+NodeViewItem::NodeViewItem(Node* n, Node *context, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
- node_(nullptr),
- context_(nullptr),
+ node_(n),
+ context_(context),
expanded_(false),
hide_titlebar_(false),
highlighted_index_(-1),
@@ -69,6 +69,24 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
setRect(title_bar_rect_);
output_connector_ = new NodeViewItemConnector(true, this);
+
+ // Set up node
+ node_->Retranslate();
+
+ foreach (const QString& input, node_->inputs()) {
+ if (node_->IsInputConnectable(input) && !node_->IsInputHidden(input)) {
+ node_inputs_.append(input);
+ }
+ }
+
+ UpdateInputConnectors();
+
+ connect(node_, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
+ connect(node_, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged);
+
+ SetNodePosition(context_->GetNodePositionInContext(node_));
+
+ SetExpanded(node_->property("expanded").toBool());
}
QPointF NodeViewItem::GetNodePosition() const
@@ -208,37 +226,6 @@ int NodeViewItem::GetIndexAt(QPointF pt) const
return -1;
}
-void NodeViewItem::SetNode(Node *n, Node *context)
-{
- if (node_) {
- disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
- disconnect(n, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged);
- }
-
- node_ = n;
- context_ = context;
-
- node_inputs_.clear();
- input_connectors_.clear();
-
- if (node_) {
- node_->Retranslate();
-
- foreach (const QString& input, node_->inputs()) {
- if (node_->IsInputConnectable(input) && !node_->IsInputHidden(input)) {
- node_inputs_.append(input);
- }
- }
-
- UpdateInputConnectors();
-
- connect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
- connect(n, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged);
- }
-
- update();
-}
-
void NodeViewItem::SetExpanded(bool e, bool hide_titlebar)
{
if (node_inputs_.isEmpty()
@@ -248,6 +235,7 @@ void NodeViewItem::SetExpanded(bool e, bool hide_titlebar)
expanded_ = e;
hide_titlebar_ = hide_titlebar;
+ node_->setProperty("expanded", e);
if (expanded_ && !node_inputs_.isEmpty()) {
// Create new rect
@@ -507,8 +495,8 @@ void NodeViewItem::SetLabelAsOutput(bool e)
NodeViewEdge *NodeViewItem::GetEdgeFromInputConnector(NodeViewItemConnector *connector)
{
- ssize_t index = -1;
- for (ssize_t i=0; iSetFlowDirection(direction_);
}
-
- // Iterate over edge items setting direction
- foreach (NodeViewEdge* edge, edges_) {
- edge->SetFlowDirection(direction_);
- }
}
void NodeViewScene::clear()
@@ -63,9 +59,6 @@ void NodeViewScene::clear()
delete it.value();
}
item_map_.clear();
-
- qDeleteAll(edges_);
- edges_.clear();
}
void NodeViewScene::SelectAll()
@@ -86,22 +79,22 @@ void NodeViewScene::DeselectAll()
}
}
+void NodeViewScene::DeleteSelected()
+{
+ NodeViewDeleteCommand* command = new NodeViewDeleteCommand();
+
+ foreach (NodeViewContext *ctx, context_map_) {
+ ctx->DeleteSelected(command);
+ }
+
+ Core::instance()->undo_stack()->push(command);
+}
+
NodeViewItem *NodeViewScene::NodeToUIObject(Node *n)
{
return item_map_.value(n);
}
-NodeViewEdge *NodeViewScene::EdgeToUIObject(Node *output, const NodeInput& input)
-{
- foreach (NodeViewEdge* edge, edges_) {
- if (edge->output() == output && edge->input() == input) {
- return edge;
- }
- }
-
- return nullptr;
-}
-
QVector NodeViewScene::GetSelectedNodes() const
{
QHash::const_iterator iterator;
@@ -118,29 +111,13 @@ QVector NodeViewScene::GetSelectedNodes() const
QVector NodeViewScene::GetSelectedItems() const
{
- QHash::const_iterator iterator;
- QVector selected;
+ QVector items;
- for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
- if (iterator.value()->isSelected()) {
- selected.append(iterator.value());
- }
+ foreach (NodeViewContext *ctx, context_map_) {
+ items.append(ctx->GetSelectedItems());
}
- return selected;
-}
-
-QVector NodeViewScene::GetSelectedEdges() const
-{
- QVector edges;
-
- foreach (NodeViewEdge* e, edges_) {
- if (e->isSelected()) {
- edges.append(e);
- }
- }
-
- return edges;
+ return items;
}
NodeViewContext *NodeViewScene::AddContext(Node *node)
diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h
index db49aca89..0ef1adfab 100644
--- a/app/widget/nodeview/nodeviewscene.h
+++ b/app/widget/nodeview/nodeviewscene.h
@@ -42,6 +42,8 @@ public:
void SelectAll();
void DeselectAll();
+ void DeleteSelected();
+
/**
* @brief Retrieve the graphical widget corresponding to a specific Node
*
@@ -54,22 +56,15 @@ public:
* in this view/scene), this function returns nullptr.
*/
NodeViewItem* NodeToUIObject(Node* n);
- NodeViewEdge *EdgeToUIObject(Node *output, const NodeInput &input);
QVector GetSelectedNodes() const;
QVector GetSelectedItems() const;
- QVector GetSelectedEdges() const;
const QHash& item_map() const
{
return item_map_;
}
- const QVector& edges() const
- {
- return edges_;
- }
-
Qt::Orientation GetFlowOrientation() const;
NodeViewCommon::FlowDirection GetFlowDirection() const;
@@ -96,8 +91,6 @@ private:
QHash item_map_;
- QVector edges_;
-
NodeGraph* graph_;
NodeViewCommon::FlowDirection direction_;
diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp
index 5d7af0263..54106070f 100644
--- a/app/widget/nodeview/nodeviewundo.cpp
+++ b/app/widget/nodeview/nodeviewundo.cpp
@@ -193,4 +193,100 @@ void NodeOverrideColorCommand::undo()
node_->SetOverrideColor(old_index_);
}
+NodeViewDeleteCommand::NodeViewDeleteCommand()
+{
+}
+
+void NodeViewDeleteCommand::AddNode(Node *node, Node *context)
+{
+ foreach (const NodePair &pair, nodes_) {
+ if (pair.first == node && pair.second == context) {
+ return;
+ }
+ }
+
+ nodes_.append(NodePair({node, context}));
+
+ for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
+ if (context->ContextContainsNode(it->second)) {
+ AddEdge(it->second, it->first);
+ }
+ }
+
+ for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
+ if (context->ContextContainsNode(it->second.node())) {
+ AddEdge(it->first, it->second);
+ }
+ }
+}
+
+void NodeViewDeleteCommand::AddEdge(Node *output, const NodeInput &input)
+{
+ foreach (const Node::OutputConnection &edge, edges_) {
+ if (edge.first == output && edge.second == input) {
+ return;
+ }
+ }
+
+ edges_.append({output, input});
+}
+
+Project *NodeViewDeleteCommand::GetRelevantProject() const
+{
+ if (!nodes_.isEmpty()) {
+ return nodes_.first().first->project();
+ }
+
+ if (!edges_.isEmpty()) {
+ return edges_.first().first->project();
+ }
+
+ return nullptr;
+}
+
+void NodeViewDeleteCommand::redo()
+{
+ foreach (const Node::OutputConnection &edge, edges_) {
+ Node::DisconnectEdge(edge.first, edge.second);
+ }
+
+ foreach (const NodePair &pair, nodes_) {
+ RemovedNode rn;
+
+ rn.node = pair.first;
+ rn.context = pair.second;
+ rn.pos = rn.context->GetNodePositionInContext(rn.node);
+
+ rn.context->RemoveNodeFromContext(rn.node);
+
+ // If node is no longer in any contexts and is not connected to anything, remove it
+ if (rn.node->parent()->GetNumberOfContextsNodeIsIn(rn.node, true) == 0
+ && rn.node->input_connections().empty()
+ && rn.node->output_connections().empty()) {
+ rn.removed_from_graph = rn.node->parent();
+ rn.node->setParent(&memory_manager_);
+ } else {
+ rn.removed_from_graph = nullptr;
+ }
+
+ removed_nodes_.append(rn);
+ }
+}
+
+void NodeViewDeleteCommand::undo()
+{
+ for (auto rn=removed_nodes_.crbegin(); rn!=removed_nodes_.crend(); rn++) {
+ if (rn->removed_from_graph) {
+ rn->node->setParent(rn->removed_from_graph);
+ }
+
+ rn->context->SetNodePositionInContext(rn->node, rn->pos);
+ }
+ removed_nodes_.clear();
+
+ for (auto edge=edges_.crbegin(); edge!=edges_.crend(); edge++) {
+ Node::ConnectEdge(edge->first, edge->second);
+ }
+}
+
}
diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h
index 7ed3e434e..567198b5b 100644
--- a/app/widget/nodeview/nodeviewundo.h
+++ b/app/widget/nodeview/nodeviewundo.h
@@ -363,6 +363,42 @@ private:
};
+class NodeViewDeleteCommand : public UndoCommand
+{
+public:
+ NodeViewDeleteCommand();
+
+ void AddNode(Node *node, Node *context);
+
+ void AddEdge(Node *output, const NodeInput &input);
+
+ virtual Project * GetRelevantProject() const override;
+
+protected:
+ virtual void redo() override;
+
+ virtual void undo() override;
+
+private:
+ using NodePair = QPair;
+
+ QVector nodes_;
+
+ QVector edges_;
+
+ struct RemovedNode {
+ Node *node;
+ Node *context;
+ QPointF pos;
+ NodeGraph *removed_from_graph;
+ };
+
+ QVector removed_nodes_;
+
+ QObject memory_manager_;
+
+};
+
}
#endif // NODEVIEWUNDO_H
From 40783bcc6d55ff12349a05bb5440e727b6bb633e Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Fri, 19 Nov 2021 15:47:31 -0800
Subject: [PATCH 08/34] reimplemented adding/removing/connecting/disconnecting
---
app/widget/nodeview/nodeview.cpp | 322 ++++++++++++------------
app/widget/nodeview/nodeview.h | 47 +---
app/widget/nodeview/nodeviewcontext.cpp | 20 +-
app/widget/nodeview/nodeviewcontext.h | 7 +
app/widget/nodeview/nodeviewedge.cpp | 3 +-
app/widget/nodeview/nodeviewitem.cpp | 15 +-
app/widget/nodeview/nodeviewitem.h | 6 +
app/widget/nodeview/nodeviewscene.h | 5 +
8 files changed, 233 insertions(+), 192 deletions(-)
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index 3da2c70f1..b27b0b862 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include "core.h"
#include "nodeviewundo.h"
@@ -44,7 +45,8 @@ NodeView::NodeView(QWidget *parent) :
HandMovableView(parent),
drop_edge_(nullptr),
create_edge_(nullptr),
- create_edge_dst_(nullptr),
+ create_edge_output_item_(nullptr),
+ create_edge_input_item_(nullptr),
create_edge_dst_temp_expanded_(false),
paste_command_(nullptr),
scale_(1.0),
@@ -87,14 +89,14 @@ void NodeView::SetContexts(const QVector &nodes)
// Remove contexts that are no longer in the list
foreach (Node *n, contexts_) {
if (!nodes.contains(n)) {
- scene_.RemoveContext(n);
+ RemoveContext(n);
}
}
// Add contexts that are now in the list
foreach (Node *n, nodes) {
if (!contexts_.contains(n)) {
- scene_.AddContext(n);
+ AddContext(n);
}
}
@@ -346,29 +348,56 @@ void NodeView::keyPressEvent(QKeyEvent *event)
void NodeView::mousePressEvent(QMouseEvent *event)
{
+ // Handle mouse press event
if (HandPress(event)) return;
+ // Get the item that the user clicked on, if any
QGraphicsItem* item = itemAt(event->pos());
if (event->button() == Qt::LeftButton) {
// Determine if user clicked on a connector
- if (NodeViewItemConnector *connector = dynamic_cast(item)) {
- NodeViewItem *attached_item = static_cast(connector->parentItem());
- if (connector->IsOutput()) {
- CreateNewEdge(attached_item, event->pos());
- return;
- } else {
- NodeViewEdge *edge_item = attached_item->GetEdgeFromInputConnector(connector);
- if (edge_item) {
- create_edge_src_ = edge_item->from_item();
- create_edge_ = edge_item;
+ NodeViewItemConnector *connector = dynamic_cast(item);
+
+ // If the user clicked on a connector OR the user is holding Ctrl
+ if (connector || (event->modifiers() & Qt::ControlModifier)) {
+ // Get the relevant item, either the one attached to the connector or the item if Ctrl+Clicked
+ NodeViewItem *attached_item = connector ? static_cast(connector->parentItem()) : dynamic_cast(item);
+
+ if (attached_item) {
+ if (connector && !connector->IsOutput() && (create_edge_ = attached_item->GetEdgeFromInputConnector(connector))) {
+ // Since inputs can only have one edge connected, we grab the existing edge, if one exists
+ create_edge_output_item_ = create_edge_->from_item();
create_edge_already_exists_ = true;
+ create_edge_from_output_ = true;
+ } else {
+ // Create a new edge from this output
+ create_edge_ = new NodeViewEdge();
+ create_edge_->SetCurved(scene_.GetEdgesAreCurved());
+ create_edge_->SetFlowDirection(scene_.GetFlowDirection());
+
+ // Set source and declare that we created this edge
+ if ((create_edge_from_output_ = (!connector || connector->IsOutput()))) {
+ // Edge is being created from output
+ create_edge_output_item_ = attached_item;
+ } else {
+ // Edge is being created from input
+ create_edge_input_item_ = attached_item;
+ create_edge_input_ = attached_item->GetInputFromInputConnector(connector);
+ }
+ create_edge_already_exists_ = false;
+
+ // Add edge to scene
+ scene_.addItem(create_edge_);
+
+ // Position edge to mouse cursor
+ PositionNewEdge(event->pos());
}
return;
}
}
}
+ // Handle selections with the right mouse button
if (event->button() == Qt::RightButton) {
if (!item || !item->isSelected()) {
// Qt doesn't do this by default for some reason
@@ -383,19 +412,16 @@ void NodeView::mousePressEvent(QMouseEvent *event)
}
}
- if (event->modifiers() & Qt::ControlModifier) {
- NodeViewItem* node_item = dynamic_cast(item);
- if (node_item) {
- CreateNewEdge(node_item, event->pos());
- return;
- }
- }
-
+ // Default QGraphicsView functionality (selecting, dragging, etc.)
super::mousePressEvent(event);
+ // For any selected item, store its position in case the user is dragging it somewhere else
auto selected_items = scene_.GetSelectedItems();
foreach (NodeViewItem *i, selected_items) {
- dragging_nodes_.insert(i, i->GetNodePosition());
+ // Ignore items attached to the cursor
+ if (!IsItemAttachedToCursor(i)) {
+ dragging_nodes_.insert(i, i->GetNodePosition());
+ }
}
}
@@ -487,23 +513,17 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
if (HandRelease(event)) return;
if (create_edge_) {
- // We are creating a new edge or moving an existing one
+ // Check if the edge was reconnected to the same place as before
MultiUndoCommand* command = new MultiUndoCommand();
- Node::OutputConnections removed_edges;
- Node::OutputConnection added_edge;
-
bool reconnected_to_itself = false;
if (create_edge_already_exists_) {
- if (create_edge_dst_input_ == create_edge_->input()) {
+ if (create_edge_output_item_ == create_edge_->from_item() && create_edge_->input() == create_edge_input_) {
reconnected_to_itself = true;
} else {
// We are moving (or removing) an existing edge
command->add_child(new NodeEdgeRemoveCommand(create_edge_->output(), create_edge_->input()));
-
- // Update contexts for edge removal
- removed_edges.push_back({create_edge_->output(), create_edge_->input()});
}
} else {
// We're creating a new edge, which means this UI object is only temporary
@@ -512,36 +532,35 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
create_edge_ = nullptr;
- if (create_edge_dst_) {
- // Clear highlight
- create_edge_dst_->SetHighlightedIndex(-1);
+ if (create_edge_output_item_ && create_edge_input_item_) {
+ // Clear highlight if we set one
+ create_edge_input_item_->SetHighlightedIndex(-1);
// Collapse if we expanded it
if (create_edge_dst_temp_expanded_) {
- create_edge_dst_->SetExpanded(false);
- create_edge_dst_->setZValue(0);
+ create_edge_input_item_->SetExpanded(false);
+ create_edge_input_item_->setZValue(0);
}
- NodeInput &creating_input = create_edge_dst_input_;
+ NodeInput &creating_input = create_edge_input_;
if (creating_input.IsValid()) {
// Make connection
if (!reconnected_to_itself) {
- Node *creating_output = create_edge_src_->GetNode();
+ Node *creating_output = create_edge_output_item_->GetNode();
if (creating_input.IsConnected()) {
Node::OutputConnection existing_edge_to_remove = {creating_input.GetConnectedOutput(), creating_input};
command->add_child(new NodeEdgeRemoveCommand(existing_edge_to_remove.first, existing_edge_to_remove.second));
- removed_edges.push_back(existing_edge_to_remove);
}
command->add_child(new NodeEdgeAddCommand(creating_output, creating_input));
- added_edge = {creating_output, creating_input};
}
creating_input.Reset();
}
- create_edge_dst_ = nullptr;
+ create_edge_output_item_ = nullptr;
+ create_edge_input_item_ = nullptr;
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
@@ -551,6 +570,21 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
MultiUndoCommand* command = new MultiUndoCommand();
if (!attached_items_.isEmpty()) {
+ Node *context = nullptr;
+
+ QList items_at_cursor = this->items(event->pos());
+ foreach (QGraphicsItem *i, items_at_cursor) {
+ if (NodeViewContext *context_item = dynamic_cast(i)) {
+ context = context_item->GetContext();
+ break;
+ }
+ }
+
+ if (!context) {
+ QToolTip::showText(QCursor::pos(), tr("Nodes must be placed inside a context."));
+ return;
+ }
+
if (paste_command_) {
// We've already "done" this command, but MultiUndoCommand prevents "redoing" twice, so we
// add it to this command (which may have extra commands added too) so that it all gets undone
@@ -558,9 +592,26 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
command->add_child(paste_command_);
paste_command_ = nullptr;
}
- }
- if (!attached_items_.isEmpty()) {
+ {
+ MultiUndoCommand *add_command = new MultiUndoCommand();
+
+ foreach (const AttachedItem &ai, attached_items_) {
+ // Add node to the same graph that the context is in
+ add_command->add_child(new NodeAddCommand(context->parent(), ai.item->GetNode()));
+
+ // Add node to the context
+ add_command->add_child(new NodeSetPositionCommand(ai.item->GetNode(), context, scene_.context_map().value(context)->MapScenePosToNodePosInContext(ai.item->pos())));
+ }
+
+ if (add_command->child_count()) {
+ add_command->redo_now();
+ command->add_child(add_command);
+ } else {
+ delete add_command;
+ }
+ }
+
{
// Dropped attached item onto an edge, connect it between them
MultiUndoCommand *drop_edge_command = new MultiUndoCommand();
@@ -586,44 +637,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
}
- {
- // Remove from context any nodes that don't specifically output to said context
- MultiUndoCommand *remove_pos_command = new MultiUndoCommand();
-
- for (const AttachedItem &attached : qAsConst(attached_items_)) {
- MultiUndoCommand *remove_pos_subcommand = new MultiUndoCommand();
- Node *attached_node = scene_.item_map().key(attached.item);
-
- bool removed = false;
- QVector relevant_contexts;
- for (Node *context : qAsConst(contexts_)) {
- if (attached_node->OutputsTo(context, true)) {
- relevant_contexts.append(context);
- } else {
- remove_pos_subcommand->add_child(new NodeRemovePositionFromContextCommand(attached_node, context));
- removed = true;
- }
- }
-
- if (removed && !relevant_contexts.isEmpty()) {
- for (Node *relevant : qAsConst(relevant_contexts)) {
- remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant)));
- }
-
- remove_pos_command->add_child(remove_pos_subcommand);
- } else {
- delete remove_pos_subcommand;
- }
- }
-
- if (remove_pos_command->child_count()) {
- remove_pos_command->redo_now();
- command->add_child(remove_pos_command);
- } else {
- delete remove_pos_command;
- }
- }
-
DetachItemsFromCursor();
}
@@ -777,20 +790,14 @@ void NodeView::ShowContextMenu(const QPoint &pos)
void NodeView::CreateNodeSlot(QAction *action)
{
- qDebug() << "STUB!";
- /*Node* new_node = NodeFactory::CreateFromMenuAction(action);
+ Node* new_node = NodeFactory::CreateFromMenuAction(action);
if (new_node) {
- paste_command_ = new MultiUndoCommand();
- paste_command_->add_child(new NodeAddCommand(graph_, new_node));
- for (Node *context : qAsConst(contexts_)) {
- paste_command_->add_child(new NodeSetPositionCommand(new_node, context, QPointF(0, 0), false));
- }
- paste_command_->add_child(new NodeViewAttachNodesToCursor(this, {new_node}));
- paste_command_->redo_now();
-
- this->setFocus();
- }*/
+ NodeViewItem *new_item = new NodeViewItem(new_node, nullptr);
+ new_item->SetFlowDirection(scene_.GetFlowDirection());
+ scene_.addItem(new_item);
+ AttachItemsToCursor({new_item});
+ }
}
void NodeView::ContextMenuSetDirection(QAction *action)
@@ -859,6 +866,15 @@ void NodeView::MoveToScenePoint(const QPointF &pos)
centerOn(pos);
}
+void NodeView::NodeRemovedFromGraph()
+{
+ Node *context = static_cast(sender());
+
+ RemoveContext(context);
+
+ contexts_.removeOne(context);
+}
+
void NodeView::AttachNodesToCursor(const QVector &nodes)
{
QVector items(nodes.size());
@@ -885,6 +901,10 @@ void NodeView::AttachItemsToCursor(const QVector& items)
void NodeView::DetachItemsFromCursor()
{
+ foreach (const AttachedItem &ai, attached_items_) {
+ delete ai.item;
+ }
+
attached_items_.clear();
}
@@ -1037,20 +1057,6 @@ Menu *NodeView::CreateAddMenu(Menu *parent)
return add_menu;
}
-void NodeView::CreateNewEdge(NodeViewItem *output_item, const QPoint &mouse_pos)
-{
- create_edge_ = new NodeViewEdge();
- create_edge_src_ = output_item;
- create_edge_already_exists_ = false;
-
- create_edge_->SetCurved(scene_.GetEdgesAreCurved());
- create_edge_->SetFlowDirection(scene_.GetFlowDirection());
-
- scene_.addItem(create_edge_);
-
- PositionNewEdge(mouse_pos);
-}
-
void NodeView::PositionNewEdge(const QPoint &pos)
{
// Determine scene coordinate
@@ -1059,62 +1065,66 @@ void NodeView::PositionNewEdge(const QPoint &pos)
// Find if the cursor is currently inside an item
NodeViewItem* item_at_cursor = dynamic_cast(itemAt(pos));
+ NodeViewItem *source_item = create_edge_from_output_ ? create_edge_output_item_ : create_edge_input_item_;
+ NodeViewItem *&opposing_item = create_edge_from_output_ ? create_edge_input_item_ : create_edge_output_item_;
+
// Filter out connecting to self
- if (item_at_cursor == create_edge_src_) {
+ if (item_at_cursor == source_item) {
item_at_cursor = nullptr;
}
// Filter out connecting to a node that connects to us
- if (item_at_cursor && item_at_cursor->GetNode()->OutputsTo(create_edge_src_->GetNode(), true)) {
+ if (item_at_cursor
+ && ((create_edge_from_output_ && item_at_cursor->GetNode()->OutputsTo(source_item->GetNode(), true))
+ || (!create_edge_from_output_ && item_at_cursor->GetNode()->InputsFrom(source_item->GetNode(), true)))) {
item_at_cursor = nullptr;
}
// If the item has changed
- if (item_at_cursor != create_edge_dst_) {
+ if (item_at_cursor != opposing_item) {
// If we had a destination active, disconnect from it since the item has changed
- if (create_edge_dst_) {
- create_edge_dst_->SetHighlightedIndex(-1);
+ if (opposing_item) {
+ opposing_item->SetHighlightedIndex(-1);
if (create_edge_dst_temp_expanded_) {
// We expanded this item, so we can un-expand it
- create_edge_dst_->SetExpanded(false);
- create_edge_dst_->setZValue(0);
+ opposing_item->SetExpanded(false);
+ opposing_item->setZValue(0);
}
}
// Set destination
- create_edge_dst_ = item_at_cursor;
+ opposing_item = item_at_cursor;
// If our destination is an item, ensure it's expanded
- if (create_edge_dst_) {
- if ((create_edge_dst_temp_expanded_ = (!create_edge_dst_->IsExpanded()))) {
- create_edge_dst_->SetExpanded(true, true);
- create_edge_dst_->setZValue(100); // Ensure item is in front
+ if (opposing_item) {
+ if (create_edge_from_output_ && (create_edge_dst_temp_expanded_ = (!create_edge_input_item_->IsExpanded()))) {
+ create_edge_input_item_->SetExpanded(true, true);
+ create_edge_input_item_->setZValue(100); // Ensure item is in front
}
}
}
// If we have a destination, highlight the appropriate input
- int highlight_index = -1;
- if (create_edge_dst_) {
- highlight_index = create_edge_dst_->GetIndexAt(scene_pt);
- create_edge_dst_->SetHighlightedIndex(highlight_index);
+ if (create_edge_from_output_) {
+ int highlight_index = -1;
+ if (create_edge_input_item_) {
+ highlight_index = create_edge_input_item_->GetIndexAt(scene_pt);
+ create_edge_input_item_->SetHighlightedIndex(highlight_index);
+ }
+
+ if (highlight_index >= 0) {
+ create_edge_input_ = create_edge_input_item_->GetInputAtIndex(highlight_index);
+ } else {
+ create_edge_input_.Reset();
+ }
}
- if (highlight_index >= 0) {
- create_edge_dst_input_ = create_edge_dst_->GetInputAtIndex(highlight_index);
- create_edge_->SetPoints(create_edge_src_->GetOutputPoint(),
- create_edge_dst_->GetInputPoint(create_edge_dst_input_.input(), create_edge_dst_input_.element()),
- true);
- } else {
- create_edge_dst_input_.Reset();
- create_edge_->SetPoints(create_edge_src_->GetOutputPoint(),
- scene_pt,
- false);
- }
+ QPointF output_point = create_edge_output_item_ ? create_edge_output_item_->GetOutputPoint() : scene_pt;
+ QPointF input_point = create_edge_input_.IsValid() ? create_edge_input_item_->GetInputPoint(create_edge_input_.input(), create_edge_input_.element()) : scene_pt;
- // Set connected to whether we have a valid input destination
- create_edge_->SetConnected(create_edge_dst_input_.IsValid());
+ create_edge_->SetPoints(output_point, input_point, create_edge_input_item_ && create_edge_input_item_->IsExpanded());
+ create_edge_->SetConnected(create_edge_output_item_ && create_edge_input_.IsValid());
}
void NodeView::GroupNodes()
@@ -1177,6 +1187,29 @@ void NodeView::PasteNodesInternal(const QVector &duplicate_nodes)
*/
}
+void NodeView::AddContext(Node *n)
+{
+ scene_.AddContext(n);
+ connect(n, &Node::RemovedFromGraph, this, &NodeView::NodeRemovedFromGraph);
+}
+
+void NodeView::RemoveContext(Node *n)
+{
+ scene_.RemoveContext(n);
+ disconnect(n, &Node::RemovedFromGraph, this, &NodeView::NodeRemovedFromGraph);
+}
+
+bool NodeView::IsItemAttachedToCursor(NodeViewItem *item) const
+{
+ foreach (const AttachedItem &ai, attached_items_) {
+ if (ai.item == item) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector &nodes) :
view_(view),
nodes_(nodes)
@@ -1198,23 +1231,4 @@ Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const
return nullptr;
}
-void NodeView::NodeViewItemPreventRemovingCommand::redo()
-{
- NodeViewItem *item = view_->scene_.item_map().value(node_);
-
- if (item) {
- old_prevent_removing_ = item->GetPreventRemoving();
- item->SetPreventRemoving(new_prevent_removing_);
- }
-}
-
-void NodeView::NodeViewItemPreventRemovingCommand::undo()
-{
- NodeViewItem *item = view_->scene_.item_map().value(node_);
-
- if (item) {
- item->SetPreventRemoving(old_prevent_removing_);
- }
-}
-
}
diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h
index c9d7e0e43..c2259a780 100644
--- a/app/widget/nodeview/nodeview.h
+++ b/app/widget/nodeview/nodeview.h
@@ -139,12 +139,16 @@ private:
Menu *CreateAddMenu(Menu *parent);
- void CreateNewEdge(NodeViewItem *output_item, const QPoint &mouse_pos);
-
void PositionNewEdge(const QPoint &pos);
void PasteNodesInternal(const QVector &duplicate_nodes = QVector());
+ void AddContext(Node *n);
+
+ void RemoveContext(Node *n);
+
+ bool IsItemAttachedToCursor(NodeViewItem *item) const;
+
class NodeViewAttachNodesToCursor : public UndoCommand
{
public:
@@ -171,43 +175,18 @@ private:
QPointF original_pos;
};
- class NodeViewItemPreventRemovingCommand : public UndoCommand
- {
- public:
- NodeViewItemPreventRemovingCommand(NodeView *view, Node *node, bool prevent_removing) :
- view_(view),
- node_(node),
- new_prevent_removing_(prevent_removing)
- {}
-
- virtual Project * GetRelevantProject() const override
- {
- return node_->project();
- }
-
- protected:
- virtual void redo() override;
-
- virtual void undo() override;
-
- private:
- NodeView *view_;
- Node *node_;
- bool new_prevent_removing_;
- bool old_prevent_removing_;
-
- };
-
QList attached_items_;
NodeViewEdge* drop_edge_;
NodeInput drop_input_;
NodeViewEdge* create_edge_;
- NodeViewItem* create_edge_src_;
- NodeViewItem* create_edge_dst_;
- NodeInput create_edge_dst_input_;
+ NodeViewItem* create_edge_output_item_;
+ NodeViewItem* create_edge_input_item_;
+ NodeInput create_edge_input_;
bool create_edge_dst_temp_expanded_;
+ bool create_edge_already_exists_;
+ bool create_edge_from_output_;
NodeViewScene scene_;
@@ -223,8 +202,6 @@ private:
double scale_;
- bool create_edge_already_exists_;
-
bool first_show_;
static const double kMinimumScale;
@@ -263,6 +240,8 @@ private slots:
void MoveToScenePoint(const QPointF &pos);
+ void NodeRemovedFromGraph();
+
void GroupNodes();
void UngroupNodes();
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
index 564e6552a..947762ee1 100644
--- a/app/widget/nodeview/nodeviewcontext.cpp
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -91,7 +91,16 @@ void NodeViewContext::RemoveChild(Node *node)
disconnect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
disconnect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
- delete item_map_.take(node);
+ NodeViewItem *item = item_map_.take(node);
+
+ // Delete edges first because the edge destructor will try to reference item (maybe that should
+ // be changed...)
+ QVector edges_to_remove = item->edges();
+ foreach (NodeViewEdge *edge, edges_to_remove) {
+ ChildInputDisconnected(edge->output(), edge->input());
+ }
+
+ delete item;
}
void NodeViewContext::ChildInputConnected(Node *output, const NodeInput &input)
@@ -190,6 +199,15 @@ QVector NodeViewContext::GetSelectedItems() const
return items;
}
+QPointF NodeViewContext::MapScenePosToNodePosInContext(const QPointF &pos) const
+{
+ for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
+ QPointF pos_inside_parent = it.value()->mapToParent(it.value()->mapFromScene(pos));
+ return NodeViewItem::ScreenToNodePoint(pos_inside_parent, flow_dir_);
+ }
+ return QPointF(0, 0);
+}
+
void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// Set pen and brush
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
index 8a84751de..62be15974 100644
--- a/app/widget/nodeview/nodeviewcontext.h
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -17,6 +17,11 @@ class NodeViewContext : public QObject, public QGraphicsRectItem
public:
NodeViewContext(Node *context, QGraphicsItem *item = nullptr);
+ Node *GetContext() const
+ {
+ return context_;
+ }
+
void UpdateRect();
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
@@ -27,6 +32,8 @@ public:
QVector GetSelectedItems() const;
+ QPointF MapScenePosToNodePosInContext(const QPointF &pos) const;
+
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
public slots:
diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp
index caf629007..794c98c52 100644
--- a/app/widget/nodeview/nodeviewedge.cpp
+++ b/app/widget/nodeview/nodeviewedge.cpp
@@ -162,7 +162,6 @@ void NodeViewEdge::UpdateCurve()
{
const QPointF &start = cached_start_;
const QPointF &end = cached_end_;
- const bool input_is_expanded = cached_input_is_expanded_;
QPainterPath path;
path.moveTo(start);
@@ -182,7 +181,7 @@ void NodeViewEdge::UpdateCurve()
cp1 = QPointF(start.x(), half_y);
}
- if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal || input_is_expanded) {
+ if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal || cached_input_is_expanded_) {
cp2 = QPointF(half_x, end.y());
} else {
cp2 = QPointF(end.x(), half_y);
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 009ea45ac..57f67ddaf 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -84,7 +84,9 @@ NodeViewItem::NodeViewItem(Node* n, Node *context, QGraphicsItem *parent) :
connect(node_, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
connect(node_, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged);
- SetNodePosition(context_->GetNodePositionInContext(node_));
+ if (context_) {
+ SetNodePosition(context_->GetNodePositionInContext(node_));
+ }
SetExpanded(node_->property("expanded").toBool());
}
@@ -493,6 +495,17 @@ void NodeViewItem::SetLabelAsOutput(bool e)
update();
}
+NodeInput NodeViewItem::GetInputFromInputConnector(NodeViewItemConnector *connector)
+{
+ for (int i=0; i &edges() const
+ {
+ return edges_;
+ }
+
/**
* @brief Set expanded state
*/
@@ -129,6 +134,7 @@ public:
void SetLabelAsOutput(bool e);
+ NodeInput GetInputFromInputConnector(NodeViewItemConnector *connector);
NodeViewEdge *GetEdgeFromInputConnector(NodeViewItemConnector *connector);
protected:
diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h
index 0ef1adfab..b9949d59c 100644
--- a/app/widget/nodeview/nodeviewscene.h
+++ b/app/widget/nodeview/nodeviewscene.h
@@ -60,6 +60,11 @@ public:
QVector GetSelectedNodes() const;
QVector GetSelectedItems() const;
+ const QHash &context_map() const
+ {
+ return context_map_;
+ }
+
const QHash& item_map() const
{
return item_map_;
From a391e6325268f46e629a2526a6b286f50d38f149 Mon Sep 17 00:00:00 2001
From: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
Date: Fri, 19 Nov 2021 16:46:39 -0800
Subject: [PATCH 09/34] cleaned up some no longer used functions
---
app/widget/nodeview/nodeview.cpp | 160 +++++++-----------------
app/widget/nodeview/nodeview.h | 25 +---
app/widget/nodeview/nodeviewcontext.cpp | 7 ++
app/widget/nodeview/nodeviewcontext.h | 2 +
app/widget/nodeview/nodeviewitem.cpp | 1 -
app/widget/nodeview/nodeviewitem.h | 12 --
app/widget/nodeview/nodeviewscene.cpp | 64 +---------
app/widget/nodeview/nodeviewscene.h | 31 +----
8 files changed, 65 insertions(+), 237 deletions(-)
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index b27b0b862..5cb1d767c 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -140,20 +140,7 @@ void NodeView::SelectAll()
ConnectSelectionChangedSignal();
- // Determine which nodes aren't selected and add them to a separate vector
- QVector new_selection;
- for (auto it=scene_.item_map().cbegin(); it!=scene_.item_map().cend(); it++) {
- Node *n = it.key();
- if (!selected_nodes_.contains(n)) {
- new_selection.append(n);
- }
- }
-
- // Add this vector to our total selection vector
- selected_nodes_.append(new_selection);
-
- // Signal new nodes
- emit NodesSelected(new_selection);
+ UpdateSelectionCache();
}
void NodeView::DeselectAll()
@@ -175,7 +162,7 @@ void NodeView::DeselectAll()
selected_nodes_.clear();
}
-void NodeView::Select(QVector nodes, bool center_view_on_item)
+void NodeView::Select(const QVector &nodes, bool center_view_on_item)
{
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
@@ -186,54 +173,21 @@ void NodeView::Select(QVector nodes, bool center_view_on_item)
scene_.DeselectAll();
- // Remove any duplicates
- QVector processed;
-
- NodeViewItem *first_item = nullptr;
-
- for (Node* n : qAsConst(nodes)) {
- if (processed.contains(n)) {
- continue;
- }
-
- processed.append(n);
-
- NodeViewItem* item = scene_.NodeToUIObject(n);
-
- if (item) {
- item->setSelected(true);
-
- if (!first_item) {
- first_item = item;
- }
-
- if (deselections.contains(n)) {
- deselections.removeOne(n);
- } else {
- new_selections.append(n);
- }
- }
+ foreach (NodeViewContext *context, scene_.context_map()) {
+ context->Select(nodes);
}
+ /*
// Center on something
+ Node *first_item = nodes.isEmpty() ? nullptr : nodes.first();
if (center_view_on_item && first_item) {
centerOn(first_item);
}
+ */
ConnectSelectionChangedSignal();
- // Emit deselect signal for any nodes that weren't in the list
- if (!deselections.isEmpty()) {
- emit NodesDeselected(deselections);
- }
-
- // Emit select signal for any nodes that weren't in the list
- if (!new_selections.isEmpty()) {
- emit NodesSelected(new_selections);
- }
-
- // Update selected list to the list we received
- selected_nodes_ = nodes;
+ UpdateSelectionCache();
}
void NodeView::CopySelected(bool cut)
@@ -256,7 +210,7 @@ void NodeView::Paste()
void NodeView::Duplicate()
{
- PasteNodesInternal(scene_.GetSelectedNodes());
+ PasteNodesInternal(selected_nodes_);
}
void NodeView::SetColorLabel(int index)
@@ -292,7 +246,7 @@ void NodeView::keyPressEvent(QKeyEvent *event)
for (Node *n : qAsConst(selected_nodes_)) {
for (Node *context : qAsConst(contexts_)) {
if (context->ContextContainsNode(n)) {
- QPointF old_pos = context->GetNodePositionInContext(n);
+ Node::Position old_pos = context->GetNodePositionInContext(n);
// Determine one pixel in scene units
double movement_amt = 1.0 / scale_;
@@ -420,7 +374,7 @@ void NodeView::mousePressEvent(QMouseEvent *event)
foreach (NodeViewItem *i, selected_items) {
// Ignore items attached to the cursor
if (!IsItemAttachedToCursor(i)) {
- dragging_nodes_.insert(i, i->GetNodePosition());
+ dragging_items_.insert(i, i->GetNodePosition());
}
}
}
@@ -554,6 +508,11 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
command->add_child(new NodeEdgeAddCommand(creating_output, creating_input));
+
+ // If the output is not in the input's context, add it now
+ if (!create_edge_input_item_->GetContext()->ContextContainsNode(creating_output)) {
+ command->add_child(new NodeSetPositionCommand(creating_output, create_edge_input_item_->GetContext(), scene_.context_map().value(create_edge_input_item_->GetContext())->MapScenePosToNodePosInContext(create_edge_output_item_->scenePos())));
+ }
}
creating_input.Reset();
@@ -640,14 +599,14 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
DetachItemsFromCursor();
}
- for (auto it=dragging_nodes_.cbegin(); it!=dragging_nodes_.cend(); it++) {
+ for (auto it=dragging_items_.cbegin(); it!=dragging_items_.cend(); it++) {
NodeViewItem *i = it.key();
QPointF current_pos = i->GetNodePosition();
if (it.value() != current_pos) {
command->add_child(new NodeSetPositionCommand(i->GetNode(), i->GetContext(), current_pos));
}
}
- dragging_nodes_.clear();
+ dragging_items_.clear();
Core::instance()->undo_stack()->pushIfHasChildren(command);
@@ -663,37 +622,42 @@ void NodeView::resizeEvent(QResizeEvent *event)
void NodeView::UpdateSelectionCache()
{
- QVector current_selection = scene_.GetSelectedNodes();
+ QVector current_selection = scene_.GetSelectedItems();
QVector selected;
QVector deselected;
// Determine which nodes are newly selected
- if (selected_nodes_.isEmpty()) {
- // All nodes in the current selection have just been selected
- selected = current_selection;
- } else {
- for (Node* n : qAsConst(current_selection)) {
- if (!selected_nodes_.contains(n)) {
- selected.append(n);
- }
+ foreach (NodeViewItem* i, current_selection) {
+ Node *n = i->GetNode();
+ if (!selected_nodes_.contains(n)) {
+ selected.append(n);
+ selected_nodes_.append(n);
}
}
// Determine which nodes are newly deselected
if (current_selection.isEmpty()) {
- // All nodes that were selected have been deselected
+ // All nodes that were selected have been deselected, so we'll just set them all to `deselected`
deselected = selected_nodes_;
} else {
- for (Node* n : qAsConst(selected_nodes_)) {
- if (!current_selection.contains(n)) {
+ foreach (Node* n, selected_nodes_) {
+ bool still_selected = false;
+
+ foreach (NodeViewItem *i, current_selection) {
+ if (i->GetNode() == n) {
+ still_selected = true;
+ break;
+ }
+ }
+
+ if (still_selected) {
deselected.append(n);
+ selected_nodes_.removeOne(n);
}
}
}
- selected_nodes_ = current_selection;
-
if (!selected.isEmpty()) {
emit NodesSelected(selected);
}
@@ -722,7 +686,7 @@ void NodeView::ShowContextMenu(const QPoint &pos)
// Label node action
QAction* label_action = m.addAction(tr("Label"));
connect(label_action, &QAction::triggered, this, [this](){
- Core::instance()->LabelNodes(scene_.GetSelectedNodes());
+ Core::instance()->LabelNodes(selected_nodes_);
});
// Grouping
@@ -807,11 +771,12 @@ void NodeView::ContextMenuSetDirection(QAction *action)
void NodeView::OpenSelectedNodeInViewer()
{
- QVector selected = scene_.GetSelectedNodes();
- ViewerOutput* viewer = selected.isEmpty() ? nullptr : dynamic_cast(selected.first());
-
- if (viewer) {
- Core::instance()->OpenNodeInViewer(viewer);
+ // Find first viewer in list of selected nodes and open it
+ foreach (Node *n, selected_nodes_) {
+ if (ViewerOutput* viewer = dynamic_cast(n)) {
+ Core::instance()->OpenNodeInViewer(viewer);
+ break;
+ }
}
}
@@ -875,17 +840,6 @@ void NodeView::NodeRemovedFromGraph()
contexts_.removeOne(context);
}
-void NodeView::AttachNodesToCursor(const QVector &nodes)
-{
- QVector items(nodes.size());
-
- for (int i=0; i& items)
{
DetachItemsFromCursor();
@@ -974,7 +928,8 @@ bool NodeView::eventFilter(QObject *object, QEvent *event)
void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector &nodes, void *userdata)
{
- writer->writeStartElement(QStringLiteral("pos"));
+ qDebug() << "STUB!";
+ /*writer->writeStartElement(QStringLiteral("pos"));
for (Node *n : nodes) {
NodeViewItem *item = scene_.item_map().value(n);
@@ -987,7 +942,7 @@ void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVec
writer->writeEndElement(); // node
}
- writer->writeEndElement(); // pos
+ writer->writeEndElement(); // pos*/
}
void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata)
@@ -1210,25 +1165,4 @@ bool NodeView::IsItemAttachedToCursor(NodeViewItem *item) const
return false;
}
-NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector &nodes) :
- view_(view),
- nodes_(nodes)
-{
-}
-
-void NodeView::NodeViewAttachNodesToCursor::redo()
-{
- view_->AttachNodesToCursor(nodes_);
-}
-
-void NodeView::NodeViewAttachNodesToCursor::undo()
-{
- view_->DetachItemsFromCursor();
-}
-
-Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const
-{
- return nullptr;
-}
-
}
diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h
index c2259a780..fd5e2c0c9 100644
--- a/app/widget/nodeview/nodeview.h
+++ b/app/widget/nodeview/nodeview.h
@@ -63,7 +63,7 @@ public:
void SelectAll();
void DeselectAll();
- void Select(QVector nodes, bool center_view_on_item);
+ void Select(const QVector &nodes, bool center_view_on_item);
void CopySelected(bool cut);
void Paste();
@@ -120,8 +120,6 @@ protected:
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata) override;
private:
- void AttachNodesToCursor(const QVector &nodes);
-
void AttachItemsToCursor(const QVector &items);
void DetachItemsFromCursor();
@@ -149,25 +147,6 @@ private:
bool IsItemAttachedToCursor(NodeViewItem *item) const;
- class NodeViewAttachNodesToCursor : public UndoCommand
- {
- public:
- NodeViewAttachNodesToCursor(NodeView* view, const QVector& nodes);
-
- virtual Project * GetRelevantProject() const override;
-
- protected:
- virtual void redo() override;
-
- virtual void undo() override;
-
- private:
- NodeView* view_;
-
- QVector nodes_;
-
- };
-
NodeViewMiniMap *minimap_;
struct AttachedItem {
@@ -198,7 +177,7 @@ private:
QVector last_set_filter_nodes_;
QMap context_offsets_;
- QMap dragging_nodes_;
+ QMap dragging_items_;
double scale_;
diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp
index 947762ee1..b608ee58b 100644
--- a/app/widget/nodeview/nodeviewcontext.cpp
+++ b/app/widget/nodeview/nodeviewcontext.cpp
@@ -186,6 +186,13 @@ void NodeViewContext::DeleteSelected(NodeViewDeleteCommand *command)
}
}
+void NodeViewContext::Select(const QVector &nodes)
+{
+ foreach (Node *n, nodes) {
+ item_map_.value(n)->setSelected(true);
+ }
+}
+
QVector NodeViewContext::GetSelectedItems() const
{
QVector items;
diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h
index 62be15974..cf49b332d 100644
--- a/app/widget/nodeview/nodeviewcontext.h
+++ b/app/widget/nodeview/nodeviewcontext.h
@@ -30,6 +30,8 @@ public:
void DeleteSelected(NodeViewDeleteCommand *command);
+ void Select(const QVector &nodes);
+
QVector GetSelectedItems() const;
QPointF MapScenePosToNodePosInContext(const QPointF &pos) const;
diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp
index 57f67ddaf..1c645601e 100644
--- a/app/widget/nodeview/nodeviewitem.cpp
+++ b/app/widget/nodeview/nodeviewitem.cpp
@@ -47,7 +47,6 @@ NodeViewItem::NodeViewItem(Node* n, Node *context, QGraphicsItem *parent) :
hide_titlebar_(false),
highlighted_index_(-1),
flow_dir_(NodeViewCommon::kLeftToRight),
- prevent_removing_(false),
label_as_output_(false)
{
// Set flags for this widget
diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h
index 974cb1b3e..60d1f3874 100644
--- a/app/widget/nodeview/nodeviewitem.h
+++ b/app/widget/nodeview/nodeviewitem.h
@@ -122,16 +122,6 @@ public:
void SetHighlightedIndex(int index);
- void SetPreventRemoving(bool e)
- {
- prevent_removing_ = e;
- }
-
- bool GetPreventRemoving() const
- {
- return prevent_removing_;
- }
-
void SetLabelAsOutput(bool e);
NodeInput GetInputFromInputConnector(NodeViewItemConnector *connector);
@@ -210,8 +200,6 @@ private:
QPointF cached_node_pos_;
- bool prevent_removing_;
-
std::vector > input_connectors_;
NodeViewItemConnector *output_connector_;
diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp
index 2e422c24b..37a226710 100644
--- a/app/widget/nodeview/nodeviewscene.cpp
+++ b/app/widget/nodeview/nodeviewscene.cpp
@@ -44,37 +44,16 @@ void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction)
}
}
-void NodeViewScene::clear()
-{
- // Deselect everything (prevents signals that a selection has changed after deleting an object)
- DeselectAll();
-
- // HACK: QGraphicsScene contains some sort of internal caching of the selected items which doesn't update unless
- // we call a function like this. That means even though we deselect all items above, QGraphicsScene will
- // continue to incorrectly signal selectionChanged() when items that were selected (but are now not) get
- // deleted. Calling this function appears to update the internal cache and prevent this.
- selectedItems();
-
- for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
- delete it.value();
- }
- item_map_.clear();
-}
-
void NodeViewScene::SelectAll()
{
- QList all_items = this->items();
-
- foreach (QGraphicsItem* i, all_items) {
+ foreach (QGraphicsItem* i, items()) {
i->setSelected(true);
}
}
void NodeViewScene::DeselectAll()
{
- QList selected_items = this->selectedItems();
-
- foreach (QGraphicsItem* i, selected_items) {
+ foreach (QGraphicsItem* i, items()) {
i->setSelected(false);
}
}
@@ -90,25 +69,6 @@ void NodeViewScene::DeleteSelected()
Core::instance()->undo_stack()->push(command);
}
-NodeViewItem *NodeViewScene::NodeToUIObject(Node *n)
-{
- return item_map_.value(n);
-}
-
-QVector NodeViewScene::GetSelectedNodes() const
-{
- QHash::const_iterator iterator;
- QVector selected;
-
- for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
- if (iterator.value()->isSelected()) {
- selected.append(iterator.key());
- }
- }
-
- return selected;
-}
-
QVector NodeViewScene::GetSelectedItems() const
{
QVector items;
@@ -151,31 +111,11 @@ void NodeViewScene::RemoveContext(Node *node)
delete context_map_.take(node);
}
-int NodeViewScene::DetermineWeight(Node *n)
-{
- QVector