diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index 97e7bd4b2..8c8fe9268 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -1,11 +1,15 @@ #include "solid.h" -SolidGenerator::SolidGenerator(QObject *parent) : - Node(parent), +SolidGenerator::SolidGenerator() : texture_(nullptr) { - texture_output_ = new NodeOutput(this); + color_input_ = new NodeInput(); + color_input_->add_data_input(NodeParam::kColor); + AddParameter(color_input_); + + texture_output_ = new NodeOutput(); texture_output_->set_data_type(NodeOutput::kTexture); + AddParameter(texture_output_); } QString SolidGenerator::Name() diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index 50e7af114..6c6f7bf62 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -9,7 +9,7 @@ class SolidGenerator : public Node { Q_OBJECT public: - SolidGenerator(QObject* parent = nullptr); + SolidGenerator(); virtual QString Name() override; virtual QString Category() override; @@ -21,6 +21,8 @@ public slots: virtual void Process(const rational &time) override; private: + NodeInput* color_input_; + NodeOutput* texture_output_; QOpenGLTexture* texture_; diff --git a/app/node/graph.cpp b/app/node/graph.cpp index 7f1bb660c..94ef78a86 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -27,6 +27,14 @@ NodeGraph::NodeGraph() } +void NodeGraph::AddNode(Node *node) +{ + node->setParent(this); + + connect(node, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); + connect(node, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); +} + const QString &NodeGraph::name() { return name_; diff --git a/app/node/graph.h b/app/node/graph.h index 520688262..e6215e86a 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -27,14 +27,21 @@ class NodeGraph : public QObject { + Q_OBJECT public: NodeGraph(); + void AddNode(Node* node); + const QString& name(); void set_name(const QString& name); QList nodes(); +signals: + void EdgeAdded(NodeEdgePtr edge); + void EdgeRemoved(NodeEdgePtr edge); + private: QString name_; }; diff --git a/app/node/input.cpp b/app/node/input.cpp index 95d5c97fa..b63c04b41 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -22,8 +22,7 @@ #include "output.h" -NodeInput::NodeInput(Node* parent) : - NodeParam(parent), +NodeInput::NodeInput() : can_accept_multiple_inputs_(false) { // Have at least one keyframe/value active at any time @@ -97,3 +96,8 @@ void NodeInput::set_keyframing(bool k) { keyframing_ = k; } + +const QList &NodeInput::inputs() +{ + return inputs_; +} diff --git a/app/node/input.h b/app/node/input.h index 29d35cdd8..952e3ed11 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -27,7 +27,7 @@ class NodeInput : public NodeParam { public: - NodeInput(Node *parent); + NodeInput(); virtual Type type() override; @@ -43,6 +43,8 @@ public: bool keyframing(); void set_keyframing(bool k); + const QList& inputs(); + private: QList inputs_; diff --git a/app/node/node.cpp b/app/node/node.cpp index 1903acecc..88fca5790 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -22,8 +22,7 @@ #include "common/qobjectlistcast.h" -Node::Node(QObject *parent) : - QObject(parent) +Node::Node() { } @@ -39,6 +38,14 @@ QString Node::Description() return QString(); } +void Node::AddParameter(NodeParam *param) +{ + param->setParent(this); + + connect(param, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); + connect(param, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); +} + void Node::InvalidateCache(const rational &start_range, const rational &end_range) { QList params = parameters(); diff --git a/app/node/node.h b/app/node/node.h index c2165dc9d..e776255d5 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -31,12 +31,14 @@ class Node : public QObject { Q_OBJECT public: - Node(QObject* parent = nullptr); + Node(); virtual QString Name() = 0; virtual QString Category(); virtual QString Description(); + void AddParameter(NodeParam* param); + /** * @brief Signal all dependent Nodes that anything cached between start_range and end_range is now invalid and * requires re-rendering @@ -71,6 +73,10 @@ public: public slots: virtual void Process(const rational& time) = 0; + +signals: + void EdgeAdded(NodeEdgePtr edge); + void EdgeRemoved(NodeEdgePtr edge); }; #endif // NODE_H diff --git a/app/node/output.cpp b/app/node/output.cpp index e9f3a8ba2..0f9f259d6 100644 --- a/app/node/output.cpp +++ b/app/node/output.cpp @@ -22,8 +22,7 @@ #include "node/node.h" -NodeOutput::NodeOutput(Node *parent) : - NodeParam(parent) +NodeOutput::NodeOutput() { } diff --git a/app/node/output.h b/app/node/output.h index e84f72146..8e2014ed8 100644 --- a/app/node/output.h +++ b/app/node/output.h @@ -26,7 +26,7 @@ class NodeOutput : public NodeParam { public: - NodeOutput(Node* parent); + NodeOutput(); virtual Type type() override; diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 424de91f0..224ea6537 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -2,12 +2,12 @@ #include "panel/panelfocusmanager.h" -ViewerOutput::ViewerOutput(QObject* parent) : - Node(parent), +ViewerOutput::ViewerOutput() : attached_viewer_(nullptr) { - texture_input_ = new NodeInput(this); + texture_input_ = new NodeInput(); texture_input_->add_data_input(NodeInput::kTexture); + AddParameter(texture_input_); } QString ViewerOutput::Name() diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 88269f4b4..f07dd4b6e 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -8,7 +8,7 @@ class ViewerOutput : public Node { Q_OBJECT public: - ViewerOutput(QObject* parent = nullptr); + ViewerOutput(); virtual QString Name() override; virtual QString Category() override; diff --git a/app/node/param.cpp b/app/node/param.cpp index 204cd5e43..683013410 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -20,12 +20,13 @@ #include "param.h" +#include + #include "node/node.h" #include "node/input.h" #include "node/output.h" -NodeParam::NodeParam(Node *parent) : - QObject(parent) +NodeParam::NodeParam() { } @@ -54,6 +55,28 @@ const QVector &NodeParam::edges() return edges_; } +bool NodeParam::AreDataTypesCompatible(NodeParam *a, NodeParam *b) +{ + // Make sure one is an input and one is an output + if (a->type() == b->type()) { + return false; + } + + NodeInput* input; + NodeOutput* output; + + // Work out which parameter is which + if (a->type() == NodeParam::kInput) { + input = static_cast(a); + output = static_cast(b); + } else { + input = static_cast(b); + output = static_cast(a); + } + + return AreDataTypesCompatible(output->data_type(), input->inputs()); +} + bool NodeParam::AreDataTypesCompatible(const NodeParam::DataType &output_type, const NodeParam::DataType &input_type) { if (input_type == output_type) { @@ -94,11 +117,21 @@ NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input) DisconnectEdge(input->edges_.first()); } + // Make sure it's not a duplicate of an edge that already exists + foreach (NodeEdgePtr existing, input->edges()) { + if (existing->output() == output) { + return nullptr; + } + } + NodeEdgePtr edge = std::make_shared(output, input); output->edges_.append(edge); input->edges_.append(edge); + // Emit a signal than an edge was added (only one signal needs emitting) + emit output->EdgeAdded(edge); + return edge; } @@ -109,6 +142,8 @@ void NodeParam::DisconnectEdge(NodeEdgePtr edge) output->edges_.removeAll(edge); input->edges_.removeAll(edge); + + emit output->EdgeRemoved(edge); } QString NodeParam::GetDefaultDataTypeName(const DataType& type) diff --git a/app/node/param.h b/app/node/param.h index b06ea1078..5f6f5a734 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -31,6 +31,7 @@ class Node; class NodeParam : public QObject { + Q_OBJECT public: enum Type { kInput, @@ -52,7 +53,7 @@ public: kAny }; - NodeParam(Node* parent); + NodeParam(); virtual Type type() = 0; @@ -65,6 +66,7 @@ public: const QVector& edges(); + static bool AreDataTypesCompatible(NodeParam* a, NodeParam* b); static bool AreDataTypesCompatible(const DataType& output_type, const DataType& input_type); static bool AreDataTypesCompatible(const DataType& output_type, const QList& input_types); @@ -73,6 +75,10 @@ public: static QString GetDefaultDataTypeName(const DataType &type); +signals: + void EdgeAdded(NodeEdgePtr edge); + void EdgeRemoved(NodeEdgePtr edge); + protected: QVector edges_; diff --git a/app/node/processor/renderer/renderer.cpp b/app/node/processor/renderer/renderer.cpp index ca8f26ef5..f85b367fc 100644 --- a/app/node/processor/renderer/renderer.cpp +++ b/app/node/processor/renderer/renderer.cpp @@ -20,8 +20,7 @@ #include "renderer.h" -RendererProcessor::RendererProcessor(QObject *parent) : - Node(parent), +RendererProcessor::RendererProcessor() : started_(false) { diff --git a/app/node/processor/renderer/renderer.h b/app/node/processor/renderer/renderer.h index b5bb8f323..4ccd050ff 100644 --- a/app/node/processor/renderer/renderer.h +++ b/app/node/processor/renderer/renderer.h @@ -34,7 +34,7 @@ public: * Constructing a Renderer object will not start any threads/backend on its own. Use Start() to do this and Stop() * when the Renderer is about to be destroyed. */ - RendererProcessor(QObject* parent = nullptr); + RendererProcessor(); virtual QString Name() override; virtual QString Category() override; diff --git a/app/widget/nodeview/CMakeLists.txt b/app/widget/nodeview/CMakeLists.txt index 5ec4d2e75..9103c574f 100644 --- a/app/widget/nodeview/CMakeLists.txt +++ b/app/widget/nodeview/CMakeLists.txt @@ -18,9 +18,11 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodeview/nodeview.h widget/nodeview/nodeview.cpp - widget/nodeview/nodeviewitem.h - widget/nodeview/nodeviewitem.cpp widget/nodeview/nodeviewedge.h widget/nodeview/nodeviewedge.cpp + widget/nodeview/nodeviewitem.h + widget/nodeview/nodeviewitem.cpp + widget/nodeview/nodeviewitemwidgetproxy.h + widget/nodeview/nodeviewitemwidgetproxy.cpp PARENT_SCOPE ) diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 66b33d72e..f8f9c9ef1 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -33,6 +33,11 @@ NodeView::NodeView(QWidget *parent) : void NodeView::SetGraph(NodeGraph *graph) { + if (graph_ != nullptr) { + disconnect(graph_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(AddEdge(NodeEdgePtr))); + disconnect(graph_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(RemoveEdge(NodeEdgePtr))); + } + // Clear the scene of all UI objects scene_.clear(); @@ -41,6 +46,9 @@ void NodeView::SetGraph(NodeGraph *graph) // If the graph is valid, add UI objects for each of its Nodes if (graph_ != nullptr) { + connect(graph_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(AddEdge(NodeEdgePtr))); + connect(graph_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(RemoveEdge(NodeEdgePtr))); + QList graph_nodes = graph_->nodes(); foreach (Node* node, graph_nodes) { @@ -61,11 +69,7 @@ void NodeView::SetGraph(NodeGraph *graph) const QVector& edges = param->edges(); foreach(NodeEdgePtr edge, edges) { - NodeViewEdge* edge_ui = new NodeViewEdge(); - - edge_ui->SetEdge(edge); - - scene_.addItem(edge_ui); + AddEdge(edge); } } } @@ -107,6 +111,22 @@ NodeViewEdge *NodeView::EdgeToUIObject(QGraphicsScene *scene, NodeEdgePtr n) return nullptr; } +void NodeView::AddEdge(NodeEdgePtr edge) +{ + NodeViewEdge* edge_ui = new NodeViewEdge(); + + edge_ui->SetEdge(edge); + + scene_.addItem(edge_ui); +} + +void NodeView::RemoveEdge(NodeEdgePtr edge) +{ + NodeViewEdge* edge_ui = EdgeToUIObject(scene(), edge); + + scene_.removeItem(edge_ui); +} + void NodeView::ItemsChanged() { QList items = scene_.items(); diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index cca154501..77e4d8204 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -44,6 +44,10 @@ private: QGraphicsScene scene_; private slots: + void AddEdge(NodeEdgePtr edge); + + void RemoveEdge(NodeEdgePtr edge); + void ItemsChanged(); }; diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index d65032ec3..7939f7aad 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -27,23 +27,20 @@ #include "common/lerp.h" #include "nodeview.h" -const int kNodeEdgeWidth = 2; - NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : QGraphicsLineItem(parent), edge_(nullptr), - moving_(false), connected_(false) { // Ensures this UI object is drawn behind other objects setZValue(-1); - setAcceptHoverEvents(true); + // Use font metrics to set edge width for basic high DPI support + edge_width_ = QFontMetrics(QFont()).height() / 12; } void NodeViewEdge::SetEdge(NodeEdgePtr edge) { - SetMoving(false); SetConnected(true); // Set the new edge pointer @@ -78,7 +75,7 @@ qreal CalculateEdgeYPoint(NodeViewItem *item, int param_index, NodeViewItem *opp void NodeViewEdge::Adjust() { - if (edge_ == nullptr || scene() == nullptr || moving_) { + if (edge_ == nullptr || scene() == nullptr) { return; } @@ -101,11 +98,6 @@ void NodeViewEdge::Adjust() )); } -void NodeViewEdge::SetMoving(bool m) -{ - moving_ = m; -} - void NodeViewEdge::SetConnected(bool c) { connected_ = c; @@ -121,7 +113,7 @@ void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti color_mode = QPalette::Disabled; } - setPen(QPen(widget->palette().color(color_mode, QPalette::Text), kNodeEdgeWidth)); + setPen(QPen(widget->palette().color(color_mode, QPalette::Text), edge_width_)); QGraphicsLineItem::paint(painter, option, widget); } diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h index 847f75731..be58620a8 100644 --- a/app/widget/nodeview/nodeviewedge.h +++ b/app/widget/nodeview/nodeviewedge.h @@ -35,7 +35,6 @@ public: void Adjust(); - void SetMoving(bool m); void SetConnected(bool c); protected: @@ -44,7 +43,8 @@ protected: private: NodeEdgePtr edge_; - bool moving_; + int edge_width_; + bool connected_; }; diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index c3a8838f9..242b2f369 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -31,11 +31,6 @@ #include "ui/icons/icons.h" #include "window/mainwindow/mainwindow.h" -const int kNodeViewItemBorderWidth = 2; -const int kNodeViewItemWidth = 200; -const int kNodeViewItemTextPadding = 4; -const int kNodeViewItemIconPadding = 12; - NodeViewItem::NodeViewItem(QGraphicsItem *parent) : QGraphicsRectItem(parent), node_(nullptr), @@ -48,13 +43,31 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) : setFlag(QGraphicsItem::ItemIsMovable); setFlag(QGraphicsItem::ItemIsSelectable); - // Use the current default font height to size this widget - // Set default "collapsed" size - title_bar_rect_ = QRectF(0, 0, kNodeViewItemWidth, font_metrics.height() + kNodeViewItemTextPadding * 2); - setRect(title_bar_rect_); + // + // We use font metrics to set all the UI measurements for DPI-awareness + // + + // Not particularly great way of using text scaling to set the width (DPI-awareness, etc.) +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + int widget_width = font_metrics.width("HHHHHHHHHHHHHHHH"); +#else + int widget_width = font_metrics.horizontalAdvance("HHHHHHHHHHHHHHHH"); +#endif + + // Set border width + node_border_width_ = font_metrics.height() / 12; // Set default node connector size node_connector_size_ = font_metrics.height() / 3; + + // Set text and icon padding + node_text_padding_ = font_metrics.height() / 6; + node_icon_padding_ = node_text_padding_ * 3; + + // Use the current default font height to size this widget + // Set default "collapsed" size + title_bar_rect_ = QRectF(0, 0, widget_width, font_metrics.height() + node_text_padding_ * 2); + setRect(title_bar_rect_); } void NodeViewItem::SetNode(Node *n) @@ -85,7 +98,7 @@ void NodeViewItem::SetExpanded(bool e) // If a node is connected, use its parameter count to set the height if (node_ != nullptr) { - full_size_rect.adjust(0, 0, 0, kNodeViewItemTextPadding*2 + font_metrics.height() * node_->ParameterCount()); + full_size_rect.adjust(0, 0, 0, node_text_padding_*2 + font_metrics.height() * node_->ParameterCount()); } // Store content_rect (the rect without the titlebar) @@ -110,10 +123,14 @@ QRectF NodeViewItem::GetParameterConnectorRect(int index) NodeParam* param = node_->ParamAt(index); QRectF connector_rect(rect().x(), - content_rect_.y() + kNodeViewItemTextPadding + font_metrics.height() / 2 - node_connector_size_ / 2, + content_rect_.y() + node_text_padding_ + font_metrics.height() / 2 - node_connector_size_ / 2, node_connector_size_, node_connector_size_); + if (index > 0) { + connector_rect.translate(0, font_metrics.height() * index); + } + // FIXME: I don't know how this will work with NodeParam::kBidirectional if (param->type() == NodeParam::kOutput) { connector_rect.translate(rect().width() - node_connector_size_, 0); @@ -132,11 +149,11 @@ QPointF NodeViewItem::GetParameterTextPoint(int index) // FIXME: I don't know how this will work with NodeParam::kBidirectional if (param->type() == NodeParam::kOutput) { - return content_rect_.topRight() + QPointF(-(node_connector_size_ + kNodeViewItemTextPadding), - kNodeViewItemTextPadding + font_metrics.ascent() + font_metrics.height()*index); + return content_rect_.topRight() + QPointF(-(node_connector_size_ + node_text_padding_), + node_text_padding_ + font_metrics.ascent() + font_metrics.height()*index); } else { - return content_rect_.topLeft() + QPointF(node_connector_size_ + kNodeViewItemTextPadding, - kNodeViewItemTextPadding + font_metrics.ascent() + font_metrics.height()*index); + return content_rect_.topLeft() + QPointF(node_connector_size_ + node_text_padding_, + node_text_padding_ + font_metrics.ascent() + font_metrics.height()*index); } } @@ -147,7 +164,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti QPalette app_pal = olive::core.main_window()->palette(); // Set up border, which will change color if selected - QPen border_pen(obj_proxy_.BorderColor(), kNodeViewItemBorderWidth); + QPen border_pen(css_proxy_.BorderColor(), node_border_width_); QPen text_pen(app_pal.color(QPalette::Text)); @@ -157,7 +174,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti if (expanded_ && node_ != nullptr) { - + // Use main widget color for node contents painter->setBrush(app_pal.window()); // Draw background rect @@ -197,7 +214,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti } // Draw rect - painter->setBrush(obj_proxy_.TitleBarColor()); + painter->setBrush(css_proxy_.TitleBarColor()); painter->drawRect(title_bar_rect_); // If selected, draw selection outline @@ -216,10 +233,10 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->setPen(text_pen); // Draw the expand icon - expand_hitbox_ = title_bar_rect_.adjusted(kNodeViewItemIconPadding, - kNodeViewItemIconPadding, - -kNodeViewItemIconPadding, - -kNodeViewItemIconPadding); + expand_hitbox_ = title_bar_rect_.adjusted(node_icon_padding_, + node_icon_padding_, + -node_icon_padding_, + -node_icon_padding_); // Make the icon rect a square expand_hitbox_.setWidth(expand_hitbox_.height()); @@ -232,10 +249,10 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti } // Draw the text in a rect (the rect is sized around text already in the constructor) - QRectF text_rect = title_bar_rect_.adjusted(kNodeViewItemIconPadding + expand_hitbox_.width() + kNodeViewItemTextPadding, - kNodeViewItemTextPadding, - -kNodeViewItemTextPadding, - -kNodeViewItemTextPadding); + QRectF text_rect = title_bar_rect_.adjusted(node_icon_padding_ + expand_hitbox_.width() + node_text_padding_, + node_text_padding_, + -node_text_padding_, + -node_text_padding_); painter->drawText(text_rect, Qt::AlignVCenter | Qt::AlignLeft, node_->Name()); } } @@ -261,42 +278,43 @@ void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) NodeParam* param = node_->ParamAt(i); + // Create draggable object + dragging_edge_ = new NodeViewEdge(); + if (param->type() == NodeParam::kOutput || param->edges().isEmpty()) { // For an output param (or an input param with no connections), we default to creating a new edge - - // Create new NodeViewEdge object for the user to create an edge - dragging_edge_ = new NodeViewEdge(); - dragging_edge_->SetMoving(true); - drag_source_ = this; drag_src_param_ = param; // Set the starting position to the current param's connector - dragging_edge_start_ = pos() + GetParameterConnectorRect(i).center(); - dragging_edge_->setLine(QLineF(dragging_edge_start_, dragging_edge_start_)); - - // Add it to the scene - scene()->addItem(dragging_edge_); + dragging_edge_start_ = mapToScene(GetParameterConnectorRect(i).center()); } else if (param->type() == NodeParam::kInput) { // For an input param, we default to moving an existing edge // (here we use the last one, which will usually also be the first) NodeEdgePtr edge = param->edges().last(); - dragging_edge_ = NodeView::EdgeToUIObject(scene(), edge); - dragging_edge_->SetMoving(true); + // Remove old edge + NodeParam::DisconnectEdge(edge); - // The starting position will be the OPPOSING param's rect - NodeOutput* opposing_param = edge->output(); - Node* opposing_node = opposing_param->parent(); - NodeViewItem* opposing_node_view_item = NodeView::NodeToUIObject(scene(), opposing_node); - dragging_edge_start_ = opposing_node_view_item->pos() + opposing_node_view_item->GetParameterConnectorRect(opposing_param->index()).center(); + // The starting position will be the OPPOSING parameter's rectangle - drag_source_ = opposing_node_view_item; - drag_src_param_ = opposing_param; + // Get the opposing parameter + drag_src_param_ = edge->output(); + // Get its Node UI object + drag_source_ = NodeView::NodeToUIObject(scene(), drag_src_param_->parent()); + + // Get the opposing parameter's rect center + dragging_edge_start_ = drag_source_->mapToScene(drag_source_->GetParameterConnectorRect(drag_src_param_->index()).center()); } + // Add it to the scene + scene()->addItem(dragging_edge_); + + // Trigger initial line setting + mouseMoveEvent(event); + return; } @@ -324,15 +342,18 @@ void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) // See if the mouse is currently inside a connector rect for (int i=0;inode()->ParameterCount();i++) { - QRectF comp_rect = drop_item->GetParameterConnectorRect(i).adjusted(-node_connector_size_, - -node_connector_size_, - node_connector_size_, - node_connector_size_); + // Make a larger "hitbox" rect to make it easier to drag into + QRectF param_hitbox = drop_item->GetParameterConnectorRect(i).adjusted(-node_connector_size_, + -node_connector_size_, + node_connector_size_, + node_connector_size_); + + // Get the parameter we're dragging into NodeParam* comp_param = drop_item->node()->ParamAt(i); - // If so, we snap inside it - if (comp_rect.contains(drop_item->mapFromScene(event->scenePos()))) { + if (param_hitbox.contains(drop_item->mapFromScene(event->scenePos())) // See if we're dragging inside the hitbox + && NodeParam::AreDataTypesCompatible(drag_src_param_, comp_param)) { // Make sure the types are compatible drag_dest_param_ = comp_param; end_point = drop_item->mapToScene(drop_item->GetParameterConnectorRect(i).center()); @@ -361,18 +382,11 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) // FIXME: Make this undoable - // If this edge had an edge, we should disconnect it now - if (dragging_edge_->edge() != nullptr) { - NodeParam::DisconnectEdge(dragging_edge_->edge()); + scene()->removeItem(dragging_edge_); - dragging_edge_->SetEdge(nullptr); - } + if (drag_dest_param_ != nullptr) { + // We dragged to somewhere, so we'll make a new connection - if (drag_dest_param_ == nullptr) { - // If we didn't drag to anywhere, just get rid of this edge - scene()->removeItem(dragging_edge_); - } else { - // If we did, create a new edge now NodeEdgePtr new_edge; if (drag_dest_param_->type() == NodeParam::kOutput) { @@ -380,8 +394,6 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } else { new_edge = NodeParam::ConnectEdge(static_cast(drag_src_param_), static_cast(drag_dest_param_)); } - - dragging_edge_->SetEdge(new_edge); } dragging_edge_ = nullptr; @@ -397,27 +409,3 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) QGraphicsRectItem::mouseReleaseEvent(event); } } - -NodeViewItemWidget::NodeViewItemWidget() -{ -} - -QColor NodeViewItemWidget::TitleBarColor() -{ - return title_bar_color_; -} - -void NodeViewItemWidget::SetTitleBarColor(QColor color) -{ - title_bar_color_ = color; -} - -QColor NodeViewItemWidget::BorderColor() -{ - return border_color_; -} - -void NodeViewItemWidget::SetBorderColor(QColor color) -{ - border_color_ = color; -} diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index c72f8c2b9..bee61490e 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -28,26 +28,7 @@ #include "node/node.h" #include "nodeviewedge.h" - -/** - * @brief A proxy object to allow NodeViewItem access to CSS functions - */ -class NodeViewItemWidget : public QWidget { - Q_OBJECT - Q_PROPERTY(QColor titlebarColor READ TitleBarColor WRITE SetTitleBarColor DESIGNABLE true) - Q_PROPERTY(QColor borderColor READ BorderColor WRITE SetBorderColor DESIGNABLE true) -public: - NodeViewItemWidget(); - - QColor TitleBarColor(); - void SetTitleBarColor(QColor color); - - QColor BorderColor(); - void SetBorderColor(QColor color); -private: - QColor title_bar_color_; - QColor border_color_; -}; +#include "nodeviewitemwidgetproxy.h" class NodeViewItem : public QGraphicsRectItem { @@ -76,7 +57,7 @@ private: Node* node_; - NodeViewItemWidget obj_proxy_; + NodeViewItemWidget css_proxy_; QRectF title_bar_rect_; @@ -94,6 +75,9 @@ private: NodeViewItem* drag_source_; int node_connector_size_; + int node_text_padding_; + int node_icon_padding_; + int node_border_width_; bool expanded_; diff --git a/app/widget/nodeview/nodeviewitemwidgetproxy.cpp b/app/widget/nodeview/nodeviewitemwidgetproxy.cpp new file mode 100644 index 000000000..15b936e7d --- /dev/null +++ b/app/widget/nodeview/nodeviewitemwidgetproxy.cpp @@ -0,0 +1,25 @@ +#include "nodeviewitemwidgetproxy.h" + +NodeViewItemWidget::NodeViewItemWidget() +{ +} + +QColor NodeViewItemWidget::TitleBarColor() +{ + return title_bar_color_; +} + +void NodeViewItemWidget::SetTitleBarColor(QColor color) +{ + title_bar_color_ = color; +} + +QColor NodeViewItemWidget::BorderColor() +{ + return border_color_; +} + +void NodeViewItemWidget::SetBorderColor(QColor color) +{ + border_color_ = color; +} diff --git a/app/widget/nodeview/nodeviewitemwidgetproxy.h b/app/widget/nodeview/nodeviewitemwidgetproxy.h new file mode 100644 index 000000000..217c33437 --- /dev/null +++ b/app/widget/nodeview/nodeviewitemwidgetproxy.h @@ -0,0 +1,29 @@ +#ifndef NODEVIEWITEMWIDGETPROXY_H +#define NODEVIEWITEMWIDGETPROXY_H + +#include + +/** + * @brief A proxy object to allow NodeViewItem access to CSS functions + * + * QGraphicsItems can't take Q_PROPERTYs for CSS stylesheet input, but QWidgets can. This is a hack to allow CSS + * properties to be set from CSS and then read by NodeViewItem. + */ +class NodeViewItemWidget : public QWidget { + Q_OBJECT + Q_PROPERTY(QColor titlebarColor READ TitleBarColor WRITE SetTitleBarColor DESIGNABLE true) + Q_PROPERTY(QColor borderColor READ BorderColor WRITE SetBorderColor DESIGNABLE true) +public: + NodeViewItemWidget(); + + QColor TitleBarColor(); + void SetTitleBarColor(QColor color); + + QColor BorderColor(); + void SetBorderColor(QColor color); +private: + QColor title_bar_color_; + QColor border_color_; +}; + +#endif // NODEVIEWITEMWIDGETPROXY_H diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index b9c4469e3..427bf03ba 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -83,10 +83,12 @@ void olive::MainWindow::ProjectOpen(Project* p) NodeGraph* graph = new NodeGraph(); graph->setParent(this); graph->set_name("New Graph"); - ViewerOutput* vo = new ViewerOutput(graph); + ViewerOutput* vo = new ViewerOutput(); vo->AttachViewer(viewer_panel2); - SolidGenerator* sg = new SolidGenerator(graph); + graph->AddNode(vo); + SolidGenerator* sg = new SolidGenerator(); NodeInput::ConnectEdge(sg->texture_output(), vo->texture_input()); + graph->AddNode(sg); task_panel->SetGraph(graph); // End test code }