From 83620173aff59495abc8e910f3194bb152c4a976 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 12 Apr 2019 01:44:49 +1000 Subject: [PATCH] ui for output rows on nodes --- effects/effect.cpp | 4 + effects/effectrow.cpp | 29 ++- effects/effectrow.h | 46 +++- effects/internal/transformeffect.cpp | 4 + nodes/nodes/nodeshader.cpp | 313 +++++++++++++-------------- ui/effectui.cpp | 67 +++--- ui/nodeui.cpp | 13 +- 7 files changed, 271 insertions(+), 205 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index 49b6f8201..db02e443c 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -128,6 +128,10 @@ Effect::Effect(Clip* c, const EffectMeta *em) : expanded_(true), texture_ctx(nullptr) { + if (em != nullptr) { + // set up UI from effect metadata + name = em->name; + } } Effect::~Effect() { diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index cf236e68c..b96349cc0 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -37,13 +37,18 @@ #include "ui/keyframenavigator.h" #include "ui/clickablelabel.h" -EffectRow::EffectRow(Effect *parent, const QString &id, const QString &name, bool savable, bool keyframable) : +EffectRow::EffectRow(Effect *parent, + const QString &id, + const QString &name, + bool savable, + bool keyframable) : QObject(parent), id_(id), name_(name), keyframable_(keyframable), keyframing_(false), - savable_(savable) + savable_(savable), + output_type_(olive::nodes::kInvalid) { Q_ASSERT(parent != nullptr); @@ -62,7 +67,9 @@ void EffectRow::AddField(EffectField *field) void EffectRow::AddNodeInput(olive::nodes::DataType type) { - accepted_datatypes_.append(type); + Q_ASSERT(output_type_ == olive::nodes::kInvalid); + + accepted_inputs_.append(type); } bool EffectRow::IsKeyframing() { @@ -107,9 +114,21 @@ void EffectRow::SetEnabled(bool enabled) } } -bool EffectRow::CanConnectNodes() +void EffectRow::SetOutputDataType(olive::nodes::DataType type) { - return !accepted_datatypes_.isEmpty(); + Q_ASSERT(accepted_inputs_.isEmpty()); + + output_type_ = type; +} + +bool EffectRow::IsNodeInput() +{ + return !accepted_inputs_.isEmpty(); +} + +bool EffectRow::IsNodeOutput() +{ + return output_type_ != olive::nodes::kInvalid; } void EffectRow::SetKeyframingEnabled(bool enabled) { diff --git a/effects/effectrow.h b/effects/effectrow.h index bcd42f117..1afc6dfa4 100644 --- a/effects/effectrow.h +++ b/effects/effectrow.h @@ -51,6 +51,7 @@ class ClickableLabel; class EffectRow : public QObject { Q_OBJECT public: + /** * @brief EffectRow Constructor * @@ -82,7 +83,11 @@ public: * Whether keyframing can be enabled on this row or not. This is true by default. Some values you may want to prevent * the user from keyframing (e.g. the filename of a VST plugin), which can be done by setting this to false. */ - EffectRow(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + EffectRow(Effect* parent, + const QString& id, + const QString& name, + bool savable = true, + bool keyframable = true); /** * @brief Retrieve the EffectField at this index. Must be less than FieldCount(). @@ -212,15 +217,33 @@ public: void SetEnabled(bool enabled); /** - * @brief Check if nodes can be connected to this input. + * @brief Check if nodes can be connected to this as an input. * * Connecting is enabled by adding an accepted node input using AddNodeInput(). * * @return * - * TRUE if nodes can be connected. + * TRUE if nodes can be connected as an input. */ - bool CanConnectNodes(); + bool IsNodeInput(); + + /** + * @brief Check if nodes can be connected to this as an output + * + * Connecting is enabled by setting an output data type in SetOutputDataType(). + * + * @return + * + * TRUE if nodes can be connected as an output + */ + bool IsNodeOutput(); + + /** + * @brief Set output data type + * + * Set the type of data this row outputs to type + */ + void SetOutputDataType(olive::nodes::DataType type); protected: /** @@ -365,9 +388,20 @@ private: QVector fields_; /** - * @brief Internal array of accepted node data types + * @brief Internal array of accepted node data types. + * + * Is mutally-exclusive with accepted_outputs_, i.e. you cannot have values added to this and also a value set in + * accepted_outputs_. */ - QVector accepted_datatypes_; + QVector accepted_inputs_; + + /** + * @brief Internal value for what kind of data this row outputs + * + * Is mutally-exclusive with accepted_inputs_, i.e. you cannot have values added to it and also a value set in + * this. + */ + olive::nodes::DataType output_type_; }; #endif // EFFECTROW_H diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index c48ec341d..c769b63e5 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -67,6 +67,10 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) opacity->SetMaximum(100); opacity->SetDefault(100); + // TEMP - Create matrix output + EffectRow* matrix_output = new EffectRow(this, "matrix", "Matrix", false, false); + matrix_output->SetOutputDataType(olive::nodes::kMatrix); + // set up gizmos top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); diff --git a/nodes/nodes/nodeshader.cpp b/nodes/nodes/nodeshader.cpp index c5118fe87..64bc64155 100644 --- a/nodes/nodes/nodeshader.cpp +++ b/nodes/nodes/nodeshader.cpp @@ -3,189 +3,184 @@ NodeShader::NodeShader(Clip* c, const EffectMeta *em) : Effect(c, em) { - if (em != nullptr) { - // set up UI from effect file - name = em->name; + if (em != nullptr && !em->filename.isEmpty() && em->internal == -1) { + QFile effect_file(em->filename); + if (effect_file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&effect_file); - if (!em->filename.isEmpty() && em->internal == -1) { - QFile effect_file(em->filename); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); + while (!reader.atEnd()) { + if (reader.name() == "field" && reader.isStartElement()) { + int type = olive::nodes::kInvalid; + QString id; + QString name; - while (!reader.atEnd()) { - if (reader.name() == "field" && reader.isStartElement()) { - int type = olive::nodes::kInvalid; - QString id; - QString name; - - // get field type - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename << "- ID, type, and name cannot be empty."; - } else { - EffectRow* field = nullptr; + if (id.isEmpty() || name.isEmpty() || type == olive::nodes::kInvalid) { + qCritical() << "Couldn't load field from" << em->filename << "- ID, type, and name cannot be empty."; + } else { + EffectRow* field = nullptr; - switch (type) { - case olive::nodes::kFloat: - { + switch (type) { + case olive::nodes::kFloat: + { - DoubleInput* double_field = new DoubleInput(this, id, name); + DoubleInput* double_field = new DoubleInput(this, id, name); - for (int i=0;iSetDefault(attr.value().toDouble()); - } else if (attr.name() == "min") { - double_field->SetMinimum(attr.value().toDouble()); - } else if (attr.name() == "max") { - double_field->SetMaximum(attr.value().toDouble()); - } + for (int i=0;iSetDefault(attr.value().toDouble()); + } else if (attr.name() == "min") { + double_field->SetMinimum(attr.value().toDouble()); + } else if (attr.name() == "max") { + double_field->SetMaximum(attr.value().toDouble()); } - - field = double_field; } - break; - case olive::nodes::kColor: - { - QColor color; - field = new ColorInput(this, id, name); + field = double_field; + } + break; + case olive::nodes::kColor: + { + QColor color; - for (int i=0;iSetValueAt(0, color); } - break; - case olive::nodes::kString: - field = new StringInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } + + field->SetValueAt(0, color); + } + break; + case olive::nodes::kString: + field = new StringInput(this, id, name); + for (int i=0;iSetValueAt(0, attr.value().toString()); } - break; - case olive::nodes::kBoolean: - field = new BoolInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value() == "1"); - } + } + break; + case olive::nodes::kBoolean: + field = new BoolInput(this, id, name); + for (int i=0;iSetValueAt(0, attr.value() == "1"); } - break; - case olive::nodes::kCombo: - { - ComboInput* combo_field = new ComboInput(this, id, name); - int combo_default_index = 0; - for (int i=0;iAddItem(reader.text().toString(), combo_item_count); - combo_item_count++; - } + combo_field->AddItem(reader.text().toString(), combo_item_count); + combo_item_count++; } - combo_field->SetValueAt(0, combo_default_index); - field = combo_field; - } - break; - case olive::nodes::kFont: - field = new FontInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - case olive::nodes::kFile: - field = new FileInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; } + combo_field->SetValueAt(0, combo_default_index); + field = combo_field; } - } else if (reader.name() == "shader" && reader.isStartElement()) { - SetFlags(Flags() | ShaderFlag); - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename; - enable_superimpose = false; + break; + case olive::nodes::kFont: + field = new FontInput(this, id, name); + for (int i=0;iSetValueAt(0, attr.value().toString()); } - break; } + break; + case olive::nodes::kFile: + field = new FileInput(this, id, name); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; } - }*/ - reader.readNext(); - } - - effect_file.close(); - } else { - qCritical() << "Failed to open effect file" << em->filename; + } + } else if (reader.name() == "shader" && reader.isStartElement()) { + SetFlags(Flags() | ShaderFlag); + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;ifilename; + enable_superimpose = false; + } + break; + } + } + }*/ + reader.readNext(); } + + effect_file.close(); + } else { + qCritical() << "Failed to open effect file" << em->filename; } } } diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 2a9e72467..bdfbeb813 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -115,41 +115,50 @@ EffectUI::EffectUI(Effect* e) : labels_.append(row_label); - layout_->addWidget(row_label, i, 0); + if (row->IsNodeOutput()) { - widgets_[i].resize(row->FieldCount()); - - QGridLayout* field_layout = new QGridLayout(); - for (int j=0;jFieldCount();j++) { - EffectField* field = row->Field(j); - - QWidget* widget = field->CreateWidget(); - - widgets_[i][j] = widget; - - field_layout->addWidget(widget, 0, j); - } - layout_->addLayout(field_layout, i, 1); - - KeyframeNavigator* nav; - - if (row->IsKeyframable()) { - - nav = new KeyframeNavigator(); - - nav->enable_keyframes(row->IsKeyframing()); - - AttachKeyframeNavigationToRow(row, nav); - - layout_->addWidget(nav, i, 2); + row_label->setAlignment(Qt::AlignRight); + layout_->addWidget(row_label, i, 2); } else { - nav = nullptr; + layout_->addWidget(row_label, i, 0); + + widgets_[i].resize(row->FieldCount()); + + QGridLayout* field_layout = new QGridLayout(); + for (int j=0;jFieldCount();j++) { + EffectField* field = row->Field(j); + + QWidget* widget = field->CreateWidget(); + + widgets_[i][j] = widget; + + field_layout->addWidget(widget, 0, j); + } + layout_->addLayout(field_layout, i, 1); + + KeyframeNavigator* nav; + + if (row->IsKeyframable()) { + + nav = new KeyframeNavigator(); + + nav->enable_keyframes(row->IsKeyframing()); + + AttachKeyframeNavigationToRow(row, nav); + + layout_->addWidget(nav, i, 2); + + } else { + + nav = nullptr; + + } + + keyframe_navigators_[i] = nav; } - - keyframe_navigators_[i] = nav; } enabled_check->setChecked(e->IsEnabled()); diff --git a/ui/nodeui.cpp b/ui/nodeui.cpp index 2d5ad970a..9a8f68c49 100644 --- a/ui/nodeui.cpp +++ b/ui/nodeui.cpp @@ -14,7 +14,7 @@ #include "ui/effectui.h" const int kRoundedRectRadius = 5; -const int kNodePlugSize = 6; +const int kNodePlugSize = 10; NodeUI::NodeUI() : central_widget_(nullptr) @@ -117,15 +117,16 @@ QVector NodeUI::GetNodeSocketRects() Effect* e = central_widget_->GetEffect(); for (int i=0;irow_count();i++) { - if (e->row(i)->CanConnectNodes()) { - int y = central_widget_->GetRowY(i); - rects.append(QRectF(rect().x(), + EffectRow* row = e->row(i); + qreal x = (row->IsNodeOutput()) ? rect().right() - kNodePlugSize : rect().x(); + int y = central_widget_->GetRowY(i); + + if (row->IsNodeInput() || row->IsNodeOutput()) { + rects.append(QRectF(x, proxy_->pos().y() + y - kNodePlugSize/2, kNodePlugSize, kNodePlugSize)); - - } } }