improved connector UI in node view
This commit is contained in:
@@ -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));
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
#include <QPen>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
#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<Block*>(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());
|
||||
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<NodeViewItem*>(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<NodeViewItem*>(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<NodeViewItem*>(child)) {
|
||||
item->SetFlowDirection(dir);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (auto child, childItems()) {
|
||||
if (NodeViewEdge *edge = dynamic_cast<NodeViewEdge*>(child)) {
|
||||
edge->SetFlowDirection(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewContext::SetCurvedEdges(bool e)
|
||||
{
|
||||
curved_edges_ = e;
|
||||
|
||||
const QList<QGraphicsItem*> &children = childItems();
|
||||
foreach (auto child, children) {
|
||||
if (NodeViewEdge *edge = dynamic_cast<NodeViewEdge*>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -128,10 +128,12 @@ void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||
painter->drawPath(path());
|
||||
|
||||
// Draw arrow
|
||||
if (!connected_) {
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(edge_color);
|
||||
painter->drawPolygon(arrow_);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewEdge::Init()
|
||||
{
|
||||
|
||||
@@ -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<NodeViewContext*>(parentItem())) {
|
||||
ctx->UpdateRect();
|
||||
}
|
||||
UpdateContextRect();
|
||||
}
|
||||
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
@@ -422,6 +408,13 @@ void NodeViewItem::ReadjustAllEdges()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewItem::UpdateContextRect()
|
||||
{
|
||||
if (NodeViewContext *ctx = dynamic_cast<NodeViewContext*>(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
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "nodeviewitemconnector.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFontMetrics>
|
||||
#include <QPalette>
|
||||
#include <QPen>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef NODEVIEWITEMCONNECTOR_H
|
||||
#define NODEVIEWITEMCONNECTOR_H
|
||||
|
||||
#include <QGraphicsPolygonItem>
|
||||
|
||||
#include "nodeviewcommon.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class NodeViewItemConnector : public QGraphicsPolygonItem
|
||||
{
|
||||
public:
|
||||
NodeViewItemConnector(QGraphicsItem *parent = nullptr);
|
||||
|
||||
void SetFlowDirection(NodeViewCommon::FlowDirection dir);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEVIEWITEMCONNECTOR_H
|
||||
@@ -38,21 +38,15 @@ void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction)
|
||||
{
|
||||
direction_ = direction;
|
||||
|
||||
{
|
||||
// Iterate over node items setting direction
|
||||
QHash<Node*, NodeViewItem*>::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_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeViewScene::clear()
|
||||
{
|
||||
@@ -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<NodeViewEdge *> 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<Node*>(sender()))->update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Node*, NodeViewContext*> context_map_;
|
||||
|
||||
QHash<Node*, NodeViewItem*> item_map_;
|
||||
@@ -129,12 +109,6 @@ private:
|
||||
|
||||
bool curved_edges_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Receiver for when a node's label has changed
|
||||
*/
|
||||
void NodeAppearanceChanged();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user