From d3bc1d4f0684bfcd6d60a995776cfd711d7c0542 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 11 Apr 2019 00:02:50 +1000 Subject: [PATCH] finished moving field data retrieving to row --- dialogs/newsequencedialog.cpp | 2 - effects/effect.cpp | 307 ++++++++++++----------- effects/effect.h | 25 ++ effects/effectfield.cpp | 40 +-- effects/effectfield.h | 62 ----- effects/effectrow.cpp | 27 +- effects/effectrow.h | 93 ++++++- effects/fields/boolfield.cpp | 4 +- effects/fields/buttonfield.cpp | 2 +- effects/fields/buttonfield.h | 2 +- effects/fields/colorfield.cpp | 3 +- effects/fields/combofield.cpp | 3 +- effects/fields/doublefield.cpp | 4 +- effects/fields/filefield.cpp | 7 +- effects/fields/filefield.h | 4 +- effects/fields/fontfield.cpp | 9 +- effects/fields/fontfield.h | 2 +- effects/fields/labelfield.cpp | 2 +- effects/fields/stringfield.cpp | 3 +- effects/fields/stringfield.h | 2 +- effects/internal/audionoiseeffect.cpp | 6 +- effects/internal/audionoiseeffect.h | 4 +- effects/internal/cornerpineffect.cpp | 46 ++-- effects/internal/cornerpineffect.h | 15 +- effects/internal/fillleftrighteffect.cpp | 3 +- effects/internal/fillleftrighteffect.h | 2 +- effects/internal/paneffect.cpp | 3 +- effects/internal/paneffect.h | 2 +- effects/internal/richtexteffect.cpp | 62 ++--- effects/internal/richtexteffect.h | 23 +- effects/internal/shakeeffect.cpp | 9 +- effects/internal/shakeeffect.h | 6 +- effects/internal/solideffect.cpp | 12 +- effects/internal/solideffect.h | 8 +- effects/internal/texteffect.cpp | 71 ++---- effects/internal/texteffect.h | 37 ++- effects/internal/timecodeeffect.cpp | 37 +-- effects/internal/timecodeeffect.h | 15 +- effects/internal/toneeffect.cpp | 12 +- effects/internal/toneeffect.h | 8 +- effects/internal/transformeffect.cpp | 123 ++++----- effects/internal/transformeffect.h | 18 +- effects/internal/voideffect.cpp | 3 +- effects/internal/volumeeffect.cpp | 3 +- effects/internal/volumeeffect.h | 2 +- effects/internal/vsthost.cpp | 7 +- effects/internal/vsthost.h | 4 +- effects/shaders/boxblur.xml | 12 +- effects/transition.cpp | 3 +- effects/transition.h | 2 +- nodes/inputs.h | 15 ++ nodes/inputs/boolinput.cpp | 14 ++ nodes/inputs/boolinput.h | 36 +++ nodes/inputs/colorinput.cpp | 12 + nodes/inputs/colorinput.h | 28 +++ nodes/inputs/comboinput.cpp | 14 ++ nodes/inputs/comboinput.h | 36 +++ nodes/inputs/doubleinput.cpp | 6 - nodes/inputs/doubleinput.h | 12 - nodes/inputs/fileinput.cpp | 12 + nodes/inputs/fileinput.h | 28 +++ nodes/inputs/fontinput.cpp | 12 + nodes/inputs/fontinput.h | 28 +++ nodes/inputs/stringinput.cpp | 12 + nodes/inputs/stringinput.h | 33 +++ nodes/inputs/vecinput.cpp | 186 ++++++++++++++ nodes/inputs/vecinput.h | 78 ++++++ nodes/nodedatatypes.h | 16 +- nodes/widgets/buttonwidget.cpp | 23 ++ nodes/widgets/buttonwidget.h | 35 +++ nodes/widgets/labelwidget.cpp | 7 + nodes/widgets/labelwidget.h | 12 + olive.pro | 21 +- panels/grapheditor.cpp | 6 +- panels/timeline.cpp | 7 + panels/timeline.h | 1 + project/footage.cpp | 4 +- ui/effectui.cpp | 10 +- 78 files changed, 1189 insertions(+), 676 deletions(-) create mode 100644 nodes/inputs.h create mode 100644 nodes/inputs/boolinput.cpp create mode 100644 nodes/inputs/boolinput.h create mode 100644 nodes/inputs/colorinput.cpp create mode 100644 nodes/inputs/colorinput.h create mode 100644 nodes/inputs/comboinput.cpp create mode 100644 nodes/inputs/comboinput.h delete mode 100644 nodes/inputs/doubleinput.cpp delete mode 100644 nodes/inputs/doubleinput.h create mode 100644 nodes/inputs/fileinput.cpp create mode 100644 nodes/inputs/fileinput.h create mode 100644 nodes/inputs/fontinput.cpp create mode 100644 nodes/inputs/fontinput.h create mode 100644 nodes/inputs/stringinput.cpp create mode 100644 nodes/inputs/stringinput.h create mode 100644 nodes/inputs/vecinput.cpp create mode 100644 nodes/inputs/vecinput.h create mode 100644 nodes/widgets/buttonwidget.cpp create mode 100644 nodes/widgets/buttonwidget.h create mode 100644 nodes/widgets/labelwidget.cpp create mode 100644 nodes/widgets/labelwidget.h diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 5d23f49af..940c046cb 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -270,8 +270,6 @@ void NewSequenceDialog::setup_ui() { videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1); interlacing_combobox = new QComboBox(videoGroupBox); interlacing_combobox->addItem(tr("None (Progressive)")); - // interlacing_combobox->addItem("Upper Field First"); - // interlacing_combobox->addItem("Lower Field First"); videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2); verticalLayout->addWidget(videoGroupBox); diff --git a/effects/effect.cpp b/effects/effect.cpp index 27608986c..478c7c2f3 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -53,6 +53,7 @@ #include "transition.h" #include "undo/undostack.h" #include "rendering/shadergenerators.h" +#include "global/timing.h" #include "effects/internal/transformeffect.h" #include "effects/internal/texteffect.h" @@ -136,153 +137,138 @@ Effect::Effect(Clip* c, const EffectMeta *em) : QXmlStreamReader reader(&effect_file); while (!reader.atEnd()) { - if (reader.name() == "row" && reader.isStartElement()) { - QString row_name; + 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()) { - qCritical() << "Couldn't load field from" << em->filename << "- ID cannot be empty."; - } else if (type == olive::nodes::kInvalid) { - qWarning() << "Invalid field type found"; - } else { - EffectField* field = nullptr; + switch (type) { + case olive::nodes::kFloat: + { - switch (type) { - case olive::nodes::kFloat: - { + DoubleInput* double_field = new DoubleInput(this, id, name); - DoubleField* double_field = new DoubleField(row, id); - - 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 ColorField(row, id); - - for (int i=0;iSetValueAt(0, color); - } - break; - case olive::nodes::kString: - field = new StringField(row, id); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - case olive::nodes::kBoolean: - field = new BoolField(row, id); - for (int i=0;iSetValueAt(0, attr.value() == "1"); - } - } - break; - case olive::nodes::kCombo: - { - ComboField* combo_field = new ComboField(row, id); - int combo_default_index = 0; - for (int i=0;iAddItem(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 FontField(row, id); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - case olive::nodes::kFile: - field = new FileField(row, id); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - } + 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); + + 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()); + } + } + 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->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; } } } else if (reader.name() == "shader" && reader.isStartElement()) { @@ -515,6 +501,7 @@ void Effect::SetEnabled(bool b) { } void Effect::load(QXmlStreamReader& stream) { + /* int row_count = 0; QString tag = stream.name().toString(); @@ -602,11 +589,13 @@ void Effect::load(QXmlStreamReader& stream) { custom_load(stream); } } + */ } void Effect::custom_load(QXmlStreamReader &) {} void Effect::save(QXmlStreamWriter& stream) { + /* stream.writeAttribute("name", meta->category + "/" + meta->name); stream.writeAttribute("enabled", QString::number(IsEnabled())); @@ -639,6 +628,7 @@ void Effect::save(QXmlStreamWriter& stream) { stream.writeEndElement(); // row } } + */ } void Effect::load_from_string(const QByteArray &s) { @@ -840,6 +830,7 @@ EffectPtr Effect::copy(Clip *c) { } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { + /* shader_program_->bind(); shader_program_->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); @@ -848,20 +839,21 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { for (int i=0;iFieldCount();j++) { EffectField* field = row->Field(j); if (!field->id().isEmpty()) { switch (field->type()) { - case EFFECT_FIELD_DOUBLE: + case EffectField::EFFECT_FIELD_DOUBLE: { DoubleField* double_field = static_cast(field); shader_program_->setUniformValue(double_field->id().toUtf8().constData(), GLfloat(double_field->GetDoubleAt(timecode))); } break; - case EFFECT_FIELD_COLOR: + case EffectField::EFFECT_FIELD_COLOR: { - ColorField* color_field = static_cast(field); + ColorField* color_field = static_cast(field); shader_program_->setUniformValue( color_field->id().toUtf8().constData(), GLfloat(color_field->GetColorAt(timecode).redF()), @@ -870,18 +862,18 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { ); } break; - case EFFECT_FIELD_BOOL: + case EffectField::EFFECT_FIELD_BOOL: shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); break; - case EFFECT_FIELD_COMBO: + case EffectField::EFFECT_FIELD_COMBO: shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); break; // can you even send a string to a uniform value? - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - case EFFECT_FIELD_UI: + case EffectField::EFFECT_FIELD_STRING: + case EffectField::EFFECT_FIELD_FONT: + case EffectField::EFFECT_FIELD_FILE: + case EffectField::EFFECT_FIELD_UI: break; } } @@ -889,6 +881,7 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { } shader_program_->release(); + */ } void Effect::process_coords(double, GLTextureCoords&, int) {} @@ -929,7 +922,7 @@ GLuint Effect::process_superimpose(QOpenGLContext* ctx, double timecode) { f->glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, tex_width_, tex_height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits() - ); + ); f->glBindTexture(GL_TEXTURE_2D, 0); @@ -1045,6 +1038,16 @@ bool Effect::are_gizmos_enabled() { return (gizmos.size() > 0); } +double Effect::Now() +{ + return playhead_to_clip_seconds(parent_clip, parent_clip->track()->sequence()->playhead); +} + +long Effect::NowInFrames() +{ + return playhead_to_clip_frame(parent_clip, parent_clip->track()->sequence()->playhead); +} + void Effect::redraw(double) { /* // run javascript @@ -1062,22 +1065,22 @@ void Effect::redraw(double) { EffectField* field = row->field(j); if (!field->id.isEmpty()) { switch (field->type) { - case EFFECT_FIELD_DOUBLE: + case EffectField::EFFECT_FIELD_DOUBLE: jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); break; - case EFFECT_FIELD_COLOR: + case EffectField::EFFECT_FIELD_COLOR: jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); break; - case EFFECT_FIELD_STRING: + case EffectField::EFFECT_FIELD_STRING: jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); break; - case EFFECT_FIELD_BOOL: + case EffectField::EFFECT_FIELD_BOOL: jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); break; - case EFFECT_FIELD_COMBO: + case EffectField::EFFECT_FIELD_COMBO: jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); break; - case EFFECT_FIELD_FONT: + case EffectField::EFFECT_FIELD_FONT: jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); break; } diff --git a/effects/effect.h b/effects/effect.h index 95ec3500a..00aacb01d 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -44,6 +44,7 @@ #include "effectrow.h" #include "effectgizmo.h" #include "rendering/qopenglshaderprogramptr.h" +#include "nodes/inputs.h" class Clip; @@ -192,6 +193,30 @@ public: void gizmo_world_to_screen(const QMatrix4x4 &matrix, const QMatrix4x4 &projection); bool are_gizmos_enabled(); + /** + * @brief Get the current clip/media time + * + * A convenience function that can be plugged into GetValueAt() to get the value wherever the appropriate Sequence's + * playhead it. + * + * @return + * + * Current clip/media time in seconds. + */ + double Now(); + + /** + * @brief Retrieve the current clip as a frame number + * + * Same as Now() but retrieves the value as a frame number (in the appropriate Sequence's frame rate) instead of + * seconds. + * + * @return + * + * The current clip time in frames + */ + long NowInFrames(); + template T randomNumber() { diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 46883e9b9..c636e3a61 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -37,16 +37,10 @@ EffectField::EffectField(EffectRow* parent, EffectFieldType t) : QObject(parent), type_(t), - id_(i), - enabled_(true), - colspan_(1) + enabled_(true) { // EffectField MUST be created with a parent. Q_ASSERT(parent != nullptr); - Q_ASSERT(!i.isEmpty() || t == EFFECT_FIELD_UI); - - // Add this field to the parent row specified - parent->AddField(this); // Set a very base default value SetValueAt(0, 0); @@ -60,17 +54,6 @@ EffectRow *EffectField::GetParentRow() return static_cast(parent()); } -int EffectField::GetColumnSpan() -{ - return colspan_; -} - -void EffectField::SetColumnSpan(int i) -{ - Q_ASSERT(i >= 1); - colspan_ = i; -} - QVariant EffectField::ConvertStringToValue(const QString &s) { return s; @@ -232,18 +215,6 @@ void EffectField::SetValueAt(double time, const QVariant &value) emit Changed(); } -double EffectField::Now() -{ - Clip* c = GetParentRow()->GetParentEffect()->parent_clip; - return playhead_to_clip_seconds(c, c->track()->sequence()->playhead); -} - -long EffectField::NowInFrames() -{ - Clip* c = GetParentRow()->GetParentEffect()->parent_clip; - return playhead_to_clip_frame(c, c->track()->sequence()->playhead); -} - void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) { if (enabled) { @@ -251,7 +222,7 @@ void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) // Create keyframe from perpetual data EffectKeyframe key; - key.time = NowInFrames(); + key.time = GetParentRow()->GetParentEffect()->NowInFrames(); key.data = persistent_data_; key.type = EFFECT_KEYFRAME_LINEAR; @@ -264,7 +235,7 @@ void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) // Convert keyframes to one "perpetual" keyframe // Set first keyframe to whatever the data is now - ca->append(new SetQVariant(&persistent_data_, persistent_data_, GetValueAt(Now()))); + ca->append(new SetQVariant(&persistent_data_, persistent_data_, GetValueAt(GetParentRow()->GetParentEffect()->Now()))); // Delete all keyframes for (int i=0;isetParent(this); + + connect(field, SIGNAL(Clicked()), this, SIGNAL(Clicked())); + connect(field, SIGNAL(Changed()), this, SIGNAL(Changed())); + fields_.append(field); } @@ -77,6 +81,27 @@ bool EffectRow::IsKeyframable() return keyframable_; } +QVariant EffectRow::GetValueAt(double timecode) +{ + Q_ASSERT(FieldCount() == 1); + + return Field(0)->GetValueAt(timecode); +} + +void EffectRow::SetValueAt(double timecode, const QVariant &value) +{ + Q_ASSERT(FieldCount() == 1); + + Field(0)->SetValueAt(timecode, value); +} + +void EffectRow::SetEnabled(bool enabled) +{ + for (int i=0;iSetEnabled(enabled); + } +} + void EffectRow::SetKeyframingEnabled(bool enabled) { if (enabled == keyframing_) { return; @@ -252,7 +277,7 @@ void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) { KeyframeDataChange* kdc = new KeyframeDataChange(field); - field->SetValueAt(field->Now(), field->GetValueAt(field->Now())); + field->SetValueAt(GetParentEffect()->Now(), field->GetValueAt(GetParentEffect()->Now())); kdc->SetNewKeyframes(); ca->append(kdc); diff --git a/effects/effectrow.h b/effects/effectrow.h index 779b437e6..7bfb4379f 100644 --- a/effects/effectrow.h +++ b/effects/effectrow.h @@ -130,6 +130,15 @@ public: */ const QString& name(); + /** + * @brief Get the unique identifier of this field set in the constructor + * + * Mostly used for saving/loading or interacting with GLSL-based shader effects (see EffectField() for more details). + * + * @return + */ + const QString& id(); + /** * @brief Get whether this row is keyframing or not * @@ -158,6 +167,63 @@ public: * @return True if this row can be keyframed. This value is set in the constructor. */ bool IsKeyframable(); + + /** + * @brief Get value at a given timecode + * + * Functions as a wrapper for EffectField::GetValueAt(). + * + * The default function is to return the result of the first EffectField on this EffectRow which should be sufficient + * for most input types. If this EffectRow has more or less than one EffectField, you must override this function in a + * derived class to provide the correct field <-> row coordination or else it will trigger an abort. + * + * @param timecode + * + * Timecode to get the value at + * + * @return + * + * The value of the first EffectField at the given timecode + */ + virtual QVariant GetValueAt(double timecode); + + /** + * @brief SetValueAt + * + * Functions as a wrapper for EffectField::SetValueAt(). + * + * The default function is to call the function of the first EffectField on this EffectRow which should be sufficient + * for most input types. If this EffectRow has more or less than one EffectField, you must override this function in a + * derived class to provide the correct field <-> row coordination or else it will trigger an abort. + * + * @param timecode + * + * Timecode to set the value at + * + * @param value + * + * Value to set at this timecode + */ + virtual void SetValueAt(double timecode, const QVariant& value); + + /** + * @brief Sets the enabled state on all EffectField objects on this row to enabled + */ + void SetEnabled(bool enabled); + +protected: + /** + * @brief Add a field to this row + * + * Ownership of the EffectField is transferred to this row and the row will free its memory. In the Effect's UI, this + * will add the field to an additional column. + * + * @param Field + * + * The field to add to this row. + */ + void AddField(EffectField* Field); + public slots: /** * @brief Go to previous keyframe @@ -194,6 +260,7 @@ public slots: */ void FocusRow(); signals: + /** * @brief Keyframing setting changed signal * @@ -204,6 +271,21 @@ signals: * True if keyframing was enabled, false if keyframing was disabled. */ void KeyframingSetChanged(bool); + + /** + * @brief Changed signal + * + * Wrapper for EffectField::Changed(). + */ + void Changed(); + + /** + * @brief Clicked signal + * + * Wrapper for EffectField::Clicked(). + */ + void Clicked(); + private slots: /** * @brief Set keyframing enabled state @@ -217,17 +299,6 @@ private slots: */ void SetKeyframingEnabled(bool); private: - /** - * @brief Add a field to this row - * - * Ownership of the EffectField is transferred to this row and the row will free its memory. In the Effect's UI, this - * will add the field to an additional column. - * - * @param Field - * - * The field to add to this row. - */ - void AddField(EffectField* Field); /** * @brief Internal unique identifier for this field set in the constructor. Access with id(). diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index 873b5f26e..f706bc08a 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -22,6 +22,8 @@ #include +#include "effects/effect.h" + BoolField::BoolField(EffectRow *parent) : EffectField(parent, EffectField::EFFECT_FIELD_BOOL) {} @@ -89,7 +91,7 @@ void BoolField::UpdateFromWidget(bool b) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), b); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), b); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/buttonfield.cpp b/effects/fields/buttonfield.cpp index 15cb436a0..2023105f3 100644 --- a/effects/fields/buttonfield.cpp +++ b/effects/fields/buttonfield.cpp @@ -22,7 +22,7 @@ #include -ButtonField::ButtonField(EffectRow *parent) : +ButtonField::ButtonField(EffectRow *parent, const QString &string) : EffectField(parent, EffectField::EFFECT_FIELD_UI), button_text_(string) {} diff --git a/effects/fields/buttonfield.h b/effects/fields/buttonfield.h index a59def70d..0cea15459 100644 --- a/effects/fields/buttonfield.h +++ b/effects/fields/buttonfield.h @@ -42,7 +42,7 @@ public: /** * @brief Reimplementation of EffectField::EffectField(). */ - ButtonField(EffectRow* parent); + ButtonField(EffectRow* parent, const QString& string); /** * @brief Set whether this pushbutton is checkable diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp index 10b2e1d0d..1797681a4 100644 --- a/effects/fields/colorfield.cpp +++ b/effects/fields/colorfield.cpp @@ -23,6 +23,7 @@ #include #include "ui/colorbutton.h" +#include "effects/effect.h" ColorField::ColorField(EffectRow* parent) : EffectField(parent, EffectField::EFFECT_FIELD_COLOR) @@ -64,7 +65,7 @@ void ColorField::UpdateFromWidget(const QColor& c) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), c); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), c); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index 173daba45..7471f7e16 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -22,6 +22,7 @@ #include +#include "effects/effect.h" #include "ui/comboboxex.h" ComboField::ComboField(EffectRow* parent) : @@ -84,7 +85,7 @@ void ComboField::UpdateFromWidget(int index) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), items_.at(index).data); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), items_.at(index).data); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 09fda4fcb..9f70bf033 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -20,7 +20,7 @@ #include "doublefield.h" -#include "effects/effectrow.h" +#include "effects/effect.h" DoubleField::DoubleField(EffectRow* parent) : EffectField(parent, EffectField::EFFECT_FIELD_DOUBLE), @@ -138,7 +138,7 @@ void DoubleField::UpdateFromWidget(double d) kdc_ = new KeyframeDataChange(this); } - SetValueAt(Now(), d); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), d); if (!ls->IsDragging() && kdc_ != nullptr) { kdc_->SetNewKeyframes(); diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index b9a21bbef..b38a035c4 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -23,9 +23,10 @@ #include #include "ui/embeddedfilechooser.h" +#include "effects/effect.h" -FileField::FileField(EffectRow* parent, const QString &id) : - EffectField(parent, id, EffectField::EFFECT_FIELD_FILE) +FileField::FileField(EffectRow* parent) : + EffectField(parent, EffectField::EFFECT_FIELD_FILE) { // Set default value to an empty string SetValueAt(0, ""); @@ -59,7 +60,7 @@ void FileField::UpdateFromWidget(const QString &s) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), s); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), s); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/filefield.h b/effects/fields/filefield.h index 3512cd555..3752fd3f7 100644 --- a/effects/fields/filefield.h +++ b/effects/fields/filefield.h @@ -24,7 +24,7 @@ #include "../effectfield.h" /** - * @brief The FileField class + * @brief The FileInput class * * An EffectField derivative that produces filenames in string and uses an EmbeddedFileChooser * as its visual representation. @@ -36,7 +36,7 @@ public: /** * @brief Reimplementation of EffectField::EffectField(). */ - FileField(EffectRow* parent, const QString& id); + FileField(EffectRow* parent); /** * @brief Get the filename at the given timecode diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp index 21c741389..7738f9bc5 100644 --- a/effects/fields/fontfield.cpp +++ b/effects/fields/fontfield.cpp @@ -24,11 +24,12 @@ #include #include "ui/comboboxex.h" +#include "effects/effect.h" -// NOTE/TODO: This shares a lot of similarity with ComboField, and could probably be a derived class of it +// NOTE/TODO: This shares a lot of similarity with ComboInput, and could probably be a derived class of it -FontField::FontField(EffectRow* parent, const QString &id) : - EffectField(parent, id, EffectField::EFFECT_FIELD_FONT) +FontField::FontField(EffectRow* parent) : + EffectField(parent, EffectField::EFFECT_FIELD_FONT) { font_list = QFontDatabase().families(); @@ -86,7 +87,7 @@ void FontField::UpdateFromWidget(const QString& s) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), s); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), s); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/fontfield.h b/effects/fields/fontfield.h index 9fa1a9305..6abd7c6c2 100644 --- a/effects/fields/fontfield.h +++ b/effects/fields/fontfield.h @@ -37,7 +37,7 @@ public: /** * @brief Reimplementation of EffectField::EffectField(). */ - FontField(EffectRow* parent, const QString& id); + FontField(EffectRow* parent); /** * @brief Get the font family name at the given timecode diff --git a/effects/fields/labelfield.cpp b/effects/fields/labelfield.cpp index 117683337..45306699a 100644 --- a/effects/fields/labelfield.cpp +++ b/effects/fields/labelfield.cpp @@ -23,7 +23,7 @@ #include LabelField::LabelField(EffectRow *parent, const QString &string) : - EffectField(parent, nullptr, EffectField::EFFECT_FIELD_UI), + EffectField(parent, EffectField::EFFECT_FIELD_UI), label_text_(string) {} diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 8b2acdb62..6c2720113 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -23,6 +23,7 @@ #include #include +#include "effects/effect.h" #include "ui/texteditex.h" #include "global/config.h" @@ -92,7 +93,7 @@ void StringField::UpdateFromWidget(const QString &s) { KeyframeDataChange* kdc = new KeyframeDataChange(this); - SetValueAt(Now(), s); + SetValueAt(GetParentRow()->GetParentEffect()->Now(), s); kdc->SetNewKeyframes(); olive::undo_stack.push(kdc); diff --git a/effects/fields/stringfield.h b/effects/fields/stringfield.h index 083021c90..4124285bb 100644 --- a/effects/fields/stringfield.h +++ b/effects/fields/stringfield.h @@ -39,7 +39,7 @@ public: * Provides a setting for whether this StringField - and its attached TextEditEx objects - should operate in rich * text or plain text mode, defaulting to rich text mode. */ - StringField(EffectRow* parent, const QString& id, bool rich_text = true); + StringField(EffectRow* parent, bool rich_text = true); /** * @brief Get the string at the given timecode diff --git a/effects/internal/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp index 2ee515a22..a1323c0f6 100644 --- a/effects/internal/audionoiseeffect.cpp +++ b/effects/internal/audionoiseeffect.cpp @@ -24,14 +24,12 @@ #include AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* amount_row = new EffectRow(this, tr("Amount")); - amount_val = new DoubleField(amount_row, "amount"); + amount_val = new DoubleInput(this, "amount", tr("Amount")); amount_val->SetMinimum(0); amount_val->SetDefault(20); amount_val->SetMaximum(100); - EffectRow* mix_row = new EffectRow(this, tr("Mix")); - mix_val = new BoolField(mix_row, "mix"); + mix_val = new BoolInput(this, "mix", tr("Mix")); mix_val->SetValueAt(0, true); } diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h index 819a02999..4e1c173ad 100644 --- a/effects/internal/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -34,8 +34,8 @@ public: int channel_count, int type) override; - DoubleField* amount_val; - BoolField* mix_val; + DoubleInput* amount_val; + BoolInput* mix_val; }; #endif // AUDIONOISEEFFECT_H diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index 814a45891..14bd4f4ba 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -27,54 +27,42 @@ CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag | Effect::ShaderFlag); - EffectRow* top_left = new EffectRow(this, tr("Top Left")); - top_left_x = new DoubleField(top_left, "topleftx"); - top_left_y = new DoubleField(top_left, "toplefty"); + top_left = new Vec2Input(this, "topleft", tr("Top Left")); - EffectRow* top_right = new EffectRow(this, tr("Top Right")); - top_right_x = new DoubleField(top_right, "toprightx"); - top_right_y = new DoubleField(top_right, "toprighty"); + top_right = new Vec2Input(this, "topright", tr("Top Right")); - EffectRow* bottom_left = new EffectRow(this, tr("Bottom Left")); - bottom_left_x = new DoubleField(bottom_left, "bottomleftx"); - bottom_left_y = new DoubleField(bottom_left, "bottomlefty"); + bottom_left = new Vec2Input(this, "bottomleft", tr("Bottom Left")); - EffectRow* bottom_right = new EffectRow(this, tr("Bottom Right")); - bottom_right_x = new DoubleField(bottom_right, "bottomrightx"); - bottom_right_y = new DoubleField(bottom_right, "bottomrighty"); + bottom_right = new Vec2Input(this, "bottomright", tr("Bottom Right")); - EffectRow* perspective_row = new EffectRow(this, tr("Perspective")); - perspective = new BoolField(perspective_row, "perspective"); + perspective = new BoolInput(this, "perspective", tr("Perspective")); perspective->SetValueAt(0, true); top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_left_gizmo->x_field1 = top_left_x; - top_left_gizmo->y_field1 = top_left_y; + top_left_gizmo->x_field1 = static_cast(top_left->Field(0)); + top_left_gizmo->y_field1 = static_cast(top_left->Field(1)); top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->x_field1 = top_right_x; - top_right_gizmo->y_field1 = top_right_y; + top_right_gizmo->x_field1 = static_cast(top_right->Field(0)); + top_right_gizmo->y_field1 = static_cast(top_right->Field(1)); bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->x_field1 = bottom_left_x; - bottom_left_gizmo->y_field1 = bottom_left_y; + bottom_left_gizmo->x_field1 = static_cast(bottom_left->Field(0)); + bottom_left_gizmo->y_field1 = static_cast(bottom_left->Field(1)); bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->x_field1 = bottom_right_x; - bottom_right_gizmo->y_field1 = bottom_right_y; + bottom_right_gizmo->x_field1 = static_cast(bottom_right->Field(0)); + bottom_right_gizmo->y_field1 = static_cast(bottom_right->Field(1)); shader_vert_path_ = "cornerpin.vert"; shader_frag_path_ = "cornerpin.frag"; } void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) { - coords.vertex_top_left += QVector3D(top_left_x->GetDoubleAt(timecode), top_left_y->GetDoubleAt(timecode), 0.0f); - - coords.vertex_top_right += QVector3D(top_right_x->GetDoubleAt(timecode), top_right_y->GetDoubleAt(timecode), 0.0f); - - coords.vertex_bottom_left += QVector3D(bottom_left_x->GetDoubleAt(timecode), bottom_left_y->GetDoubleAt(timecode), 0.0f); - - coords.vertex_bottom_right += QVector3D(bottom_right_x->GetDoubleAt(timecode), bottom_right_y->GetDoubleAt(timecode), 0.0f); + coords.vertex_top_left += top_left->GetVector2DAt(timecode); + coords.vertex_top_right += top_right->GetVector2DAt(timecode); + coords.vertex_bottom_left += bottom_left->GetVector2DAt(timecode); + coords.vertex_bottom_right += bottom_right->GetVector2DAt(timecode); } void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) { diff --git a/effects/internal/cornerpineffect.h b/effects/internal/cornerpineffect.h index 50ea31a95..573164254 100644 --- a/effects/internal/cornerpineffect.h +++ b/effects/internal/cornerpineffect.h @@ -31,15 +31,12 @@ public: void process_shader(double timecode, GLTextureCoords& coords, int iterations); void gizmo_draw(double timecode, GLTextureCoords& coords); private: - DoubleField* top_left_x; - DoubleField* top_left_y; - DoubleField* top_right_x; - DoubleField* top_right_y; - DoubleField* bottom_left_x; - DoubleField* bottom_left_y; - DoubleField* bottom_right_x; - DoubleField* bottom_right_y; - BoolField* perspective; + Vec2Input* top_left; + Vec2Input* top_right; + Vec2Input* bottom_left; + Vec2Input* bottom_right; + + BoolInput* perspective; EffectGizmo* top_left_gizmo; EffectGizmo* top_right_gizmo; diff --git a/effects/internal/fillleftrighteffect.cpp b/effects/internal/fillleftrighteffect.cpp index 34709fe79..bbc04285e 100644 --- a/effects/internal/fillleftrighteffect.cpp +++ b/effects/internal/fillleftrighteffect.cpp @@ -26,8 +26,7 @@ enum FillType { }; FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* type_row = new EffectRow(this, tr("Type")); - fill_type = new ComboField(type_row, "type"); + fill_type = new ComboInput(this, "type", tr("Type")); fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT); fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT); } diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h index 64b126caa..a80ae0227 100644 --- a/effects/internal/fillleftrighteffect.h +++ b/effects/internal/fillleftrighteffect.h @@ -34,7 +34,7 @@ public: int channel_count, int type) override; private: - ComboField* fill_type; + ComboInput* fill_type; }; #endif // FILLLEFTRIGHTEFFECT_H diff --git a/effects/internal/paneffect.cpp b/effects/internal/paneffect.cpp index 72a988f5c..57b55074b 100644 --- a/effects/internal/paneffect.cpp +++ b/effects/internal/paneffect.cpp @@ -29,8 +29,7 @@ #include "ui/collapsiblewidget.h" PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* pan_row = new EffectRow(this, tr("Pan")); - pan_val = new DoubleField(pan_row, "pan"); + pan_val = new DoubleInput(this, "pan", tr("Pan")); pan_val->SetMinimum(-100); pan_val->SetDefault(0); pan_val->SetMaximum(100); diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h index ac29d9e45..f0765ba24 100644 --- a/effects/internal/paneffect.h +++ b/effects/internal/paneffect.h @@ -34,7 +34,7 @@ public: int channel_count, int type) override; - DoubleField* pan_val; + DoubleInput* pan_val; }; #endif // PANEFFECT_H diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index cc8b822d3..b773048a8 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -39,60 +39,38 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : { SetFlags(Effect::SuperimposeFlag); - EffectRow* text_row = new EffectRow(this, tr("Text")); - text_val = new StringField(text_row, "text"); - text_val->SetColumnSpan(2); + text_val = new StringInput(this, "text", tr("Text")); - EffectRow* padding_row = new EffectRow(this, tr("Padding")); - padding_field = new DoubleField(padding_row, "padding"); - padding_field->SetColumnSpan(2); + padding_field = new DoubleInput(this, "padding", tr("Padding")); - EffectRow* position_row = new EffectRow(this, tr("Position")); - position_x = new DoubleField(position_row, "posx"); - position_y = new DoubleField(position_row, "posy"); + position = new Vec2Input(this, "pos", tr("Position")); - EffectRow* vertical_align_row = new EffectRow(this, tr("Vertical Align:")); - vertical_align = new ComboField(vertical_align_row, "valign"); + vertical_align = new ComboInput(this, "valign", tr("Vertical Align:")); vertical_align->AddItem(tr("Top"), Qt::AlignTop); vertical_align->AddItem(tr("Center"), Qt::AlignCenter); vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom); vertical_align->SetValueAt(0, Qt::AlignCenter); - vertical_align->SetColumnSpan(2); - EffectRow* autoscroll_row = new EffectRow(this, tr("Auto-Scroll")); - autoscroll = new ComboField(autoscroll_row, "autoscroll"); + autoscroll = new ComboInput(this, "autoscroll", tr("Auto-Scroll")); autoscroll->AddItem(tr("Off"), SCROLL_OFF); autoscroll->AddItem(tr("Up"), SCROLL_UP); autoscroll->AddItem(tr("Down"), SCROLL_DOWN); autoscroll->AddItem(tr("Left"), SCROLL_LEFT); autoscroll->AddItem(tr("Right"), SCROLL_RIGHT); - autoscroll->SetColumnSpan(2); - EffectRow* shadow_row = new EffectRow(this, tr("Shadow")); - shadow_bool = new BoolField(shadow_row, "shadow"); - shadow_bool->SetColumnSpan(2); + shadow_bool = new BoolInput(this, "shadow", tr("Shadow")); - EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color")); - shadow_color = new ColorField(shadow_color_row, "shadowcolor"); - shadow_color->SetColumnSpan(2); + shadow_color = new ColorInput(this, "shadowcolor", tr("Shadow Color")); - EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle")); - shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); - shadow_angle->SetColumnSpan(2); + shadow_angle = new DoubleInput(this, "shadowangle", tr("Shadow Angle")); - EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance")); - shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); - shadow_distance->SetColumnSpan(2); + shadow_distance = new DoubleInput(this, "shadowdistance", tr("Shadow Distance")); shadow_distance->SetMinimum(0); - EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness")); - shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); - shadow_softness->SetColumnSpan(2); + shadow_softness = new DoubleInput(this, "shadowsoftness", tr("Shadow Softness")); shadow_softness->SetMinimum(0); - EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity")); - shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); - shadow_opacity->SetColumnSpan(2); + shadow_opacity = new DoubleInput(this, "shadowopacity", tr("Shadow Opacity")); shadow_opacity->SetMinimum(0); shadow_opacity->SetMaximum(100); @@ -120,8 +98,8 @@ void RichTextEffect::redraw(double timecode) td.setHtml(text_val->GetStringAt(timecode)); td.setTextWidth(width); - int translate_x = qRound(position_x->GetDoubleAt(timecode) + padding); - int translate_y = qRound(position_y->GetDoubleAt(timecode) + padding); + QPoint translation = position->GetVector2DAt(timecode).toPoint(); + translation += {padding, padding}; int doc_height = qRound(td.size().height()); @@ -138,9 +116,9 @@ void RichTextEffect::redraw(double timecode) // If we're not auto-scrolling the vertical direction, respect the vertical alignment if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) { - translate_y += height / 2 - doc_height / 2; + translation.setY(translation.y() + height / 2 - doc_height / 2); } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) { - translate_y += height - doc_height; + translation.setY(translation.y() + height - doc_height); } // Check if we are autoscrolling @@ -151,7 +129,7 @@ void RichTextEffect::redraw(double timecode) } int doc_width = qRound(td.size().width()); - translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress); + translation.setX(translation.x() + qRound(-doc_width + (img.width() + doc_width) * scroll_progress)); } } else if (auto_scroll_dir == SCROLL_UP || auto_scroll_dir == SCROLL_DOWN) { @@ -162,13 +140,13 @@ void RichTextEffect::redraw(double timecode) scroll_progress = 1.0 - scroll_progress; } - translate_y += qRound(-doc_height + (img.height() + doc_height)*scroll_progress); + translation.setY(translation.y() + qRound(-doc_height + (img.height() + doc_height)*scroll_progress)); } QRect clip_rect = img.rect(); - clip_rect.translate(-translate_x, -translate_y); - p.translate(translate_x, translate_y); + clip_rect.translate(-translation); + p.translate(translation); img.fill(Qt::transparent); @@ -208,5 +186,5 @@ void RichTextEffect::redraw(double timecode) bool RichTextEffect::AlwaysUpdate() { - return autoscroll->GetValueAt(autoscroll->Now()).toInt() != SCROLL_OFF; + return autoscroll->GetValueAt(Now()).toInt() != SCROLL_OFF; } diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h index 62c1ecb1b..3853d07ac 100644 --- a/effects/internal/richtexteffect.h +++ b/effects/internal/richtexteffect.h @@ -31,19 +31,18 @@ public: protected: virtual bool AlwaysUpdate() override; private: - StringField* text_val; - DoubleField* padding_field; - DoubleField* position_x; - DoubleField* position_y; - ComboField* vertical_align; - ComboField* autoscroll; + StringInput* text_val; + DoubleInput* padding_field; + Vec2Input* position; + ComboInput* vertical_align; + ComboInput* autoscroll; - BoolField* shadow_bool; - DoubleField* shadow_angle; - DoubleField* shadow_distance; - ColorField* shadow_color; - DoubleField* shadow_softness; - DoubleField* shadow_opacity; + BoolInput* shadow_bool; + DoubleInput* shadow_angle; + DoubleInput* shadow_distance; + ColorInput* shadow_color; + DoubleInput* shadow_softness; + DoubleInput* shadow_opacity; }; #endif // RICHTEXTEFFECT_H diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index 32b103969..786812e9d 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -35,18 +35,15 @@ ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); - EffectRow* intensity_row = new EffectRow(this, tr("Intensity")); - intensity_val = new DoubleField(intensity_row, "intensity"); + intensity_val = new DoubleInput(this, "intensity", tr("Intensity")); intensity_val->SetMinimum(0); intensity_val->SetDefault(25); - EffectRow* rotation_row = new EffectRow(this, tr("Rotation")); - rotation_val = new DoubleField(rotation_row, "rotation"); + rotation_val = new DoubleInput(this, "rotation", tr("Rotation")); rotation_val->SetMinimum(0); rotation_val->SetDefault(10); - EffectRow* frequency_row = new EffectRow(this, tr("Frequency")); - frequency_val = new DoubleField(frequency_row, "frequency"); + frequency_val = new DoubleInput(this, "frequency", tr("Frequency")); frequency_val->SetMinimum(0); frequency_val->SetDefault(5); diff --git a/effects/internal/shakeeffect.h b/effects/internal/shakeeffect.h index bed1ff55a..e0bea64fc 100644 --- a/effects/internal/shakeeffect.h +++ b/effects/internal/shakeeffect.h @@ -31,9 +31,9 @@ public: ShakeEffect(Clip* c, const EffectMeta* em); virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override; - DoubleField* intensity_val; - DoubleField* rotation_val; - DoubleField* frequency_val; + DoubleInput* intensity_val; + DoubleInput* rotation_val; + DoubleInput* frequency_val; private: double random_vals[RANDOM_VAL_SIZE]; }; diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp index c8359fb7b..1fb51f51b 100644 --- a/effects/internal/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -40,24 +40,20 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : SetFlags(Effect::SuperimposeFlag); // Field for solid type - EffectRow* type_row = new EffectRow(this, tr("Type")); - solid_type = new ComboField(type_row, "type"); + solid_type = new ComboInput(this, "type", tr("Type")); solid_type->AddItem(tr("Solid Color"), SOLID_TYPE_COLOR); solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS); solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); - EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); - opacity_field = new DoubleField(opacity_row, "opacity"); + opacity_field = new DoubleInput(this, "opacity", tr("Opacity")); opacity_field->SetMinimum(0); opacity_field->SetDefault(100); opacity_field->SetMaximum(100); - EffectRow* solid_color_row = new EffectRow(this, tr("Color")); - solid_color_field = new ColorField(solid_color_row, "color"); + solid_color_field = new ColorInput(this, "color", tr("Color")); solid_color_field->SetValueAt(0, QColor(Qt::red)); - EffectRow* checkerboard_size = new EffectRow(this, tr("Checkerboard Size")); - checkerboard_size_field = new DoubleField(checkerboard_size, "checker_size"); + checkerboard_size_field = new DoubleInput(this, "checker_size", tr("Checkerboard Size")); checkerboard_size_field->SetMinimum(1); checkerboard_size_field->SetDefault(10); diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h index a52977da9..26ca04351 100644 --- a/effects/internal/solideffect.h +++ b/effects/internal/solideffect.h @@ -41,10 +41,10 @@ public: private slots: void ui_update(const QVariant &d); private: - ComboField* solid_type; - ColorField* solid_color_field; - DoubleField* opacity_field; - DoubleField* checkerboard_size_field; + ComboInput* solid_type; + ColorInput* solid_color_field; + DoubleInput* opacity_field; + DoubleInput* checkerboard_size_field; }; #endif // SOLIDEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index d957dfd5b..458ee4d4a 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -47,85 +47,52 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : { SetFlags(Effect::SuperimposeFlag); - EffectRow* text_field = new EffectRow(this, tr("Text")); - text_val = new StringField(text_field, "text", false); - text_val->SetColumnSpan(2); + text_val = new StringInput(this, "text", tr("Text"), false); - EffectRow* font_row = new EffectRow(this, tr("Font")); - set_font_combobox = new FontField(font_row, "font"); - set_font_combobox->SetColumnSpan(2); + set_font_combobox = new FontInput(this, "font", tr("Font")); - EffectRow* size_row = new EffectRow(this, tr("Size")); - size_val = new DoubleField(size_row, "size"); + size_val = new DoubleInput(this, "size", tr("Size")); size_val->SetMinimum(0); - size_val->SetColumnSpan(2); - EffectRow* color_row = new EffectRow(this, tr("Color")); - set_color_button = new ColorField(color_row, "color"); - set_color_button->SetColumnSpan(2); + set_color_button = new ColorInput(this, "color", tr("Color")); - EffectRow* alignment_row = new EffectRow(this, tr("Alignment")); - halign_field = new ComboField(alignment_row, "halign"); + halign_field = new ComboInput(this, "halign", tr("Horizontal Alignment")); halign_field->AddItem(tr("Left"), Qt::AlignLeft); halign_field->AddItem(tr("Center"), Qt::AlignHCenter); halign_field->AddItem(tr("Right"), Qt::AlignRight); halign_field->AddItem(tr("Justify"), Qt::AlignJustify); - valign_field = new ComboField(alignment_row, "valign"); + valign_field = new ComboInput(this, "valign", tr("Vertical Alignment")); valign_field->AddItem(tr("Top"), Qt::AlignTop); valign_field->AddItem(tr("Center"), Qt::AlignVCenter); valign_field->AddItem(tr("Bottom"), Qt::AlignBottom); - EffectRow* word_wrap_row = new EffectRow(this, tr("Word Wrap")); - word_wrap_field = new BoolField(word_wrap_row, "wordwrap"); - word_wrap_field->SetColumnSpan(2); + word_wrap_field = new BoolInput(this, "wordwrap", tr("Word Wrap")); - EffectRow* padding_row = new EffectRow(this, tr("Padding")); - padding_field = new DoubleField(padding_row, "padding"); - padding_field->SetColumnSpan(2); + padding_field = new DoubleInput(this, "padding", tr("Padding")); - EffectRow* position_row = new EffectRow(this, tr("Position")); - position_x = new DoubleField(position_row, "posx"); - position_y = new DoubleField(position_row, "posy"); + position = new Vec2Input(this, "pos", tr("Position")); - EffectRow* outline_row = new EffectRow(this, tr("Outline")); - outline_bool = new BoolField(outline_row, "outline"); - outline_bool->SetColumnSpan(2); + outline_bool = new BoolInput(this, "outline", tr("Outline")); - EffectRow* outline_color_row = new EffectRow(this, tr("Outline Color")); - outline_color = new ColorField(outline_color_row, "outlinecolor"); - outline_color->SetColumnSpan(2); + outline_color = new ColorInput(this, "outlinecolor", tr("Outline Color")); - EffectRow* outline_width_row = new EffectRow(this, tr("Outline Width")); - outline_width = new DoubleField(outline_width_row, "outlinewidth"); - outline_width->SetColumnSpan(2); + outline_width = new DoubleInput(this, "outlinewidth", tr("Outline Width")); outline_width->SetMinimum(0); - EffectRow* shadow_row = new EffectRow(this, tr("Shadow")); - shadow_bool = new BoolField(shadow_row, "shadow"); - shadow_bool->SetColumnSpan(2); + shadow_bool = new BoolInput(this, "shadow", tr("Shadow")); - EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color")); - shadow_color = new ColorField(shadow_color_row, "shadowcolor"); - shadow_color->SetColumnSpan(2); + shadow_color = new ColorInput(this, "shadowcolor", tr("Shadow Color")); - EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle")); - shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); - shadow_angle->SetColumnSpan(2); + shadow_angle = new DoubleInput(this, "shadowangle", tr("Shadow Angle")); - EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance")); - shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); - shadow_distance->SetColumnSpan(2); + shadow_distance = new DoubleInput(this, "shadowdistance", tr("Shadow Distance")); shadow_distance->SetMinimum(0); - EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness")); - shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); - shadow_softness->SetColumnSpan(2); + shadow_softness = new DoubleInput(this, "shadowsoftness", tr("Shadow Softness")); shadow_softness->SetMinimum(0); - EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity")); - shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); - shadow_opacity->SetColumnSpan(2); + shadow_opacity = new DoubleInput(this, "shadowopacity", tr("Shadow Opacity")); shadow_opacity->SetMinimum(0); shadow_opacity->SetMaximum(100); @@ -252,7 +219,7 @@ void TextEffect::redraw(double timecode) { path.addText(text_x, text_y, font, lines.at(i)); } - path.translate(position_x->GetDoubleAt(timecode) + padding, position_y->GetDoubleAt(timecode) + padding); + path.translate(position->GetVector2DAt(timecode).toPointF() + QPointF(padding, padding)); // draw software shadow if (shadow_bool->GetBoolAt(timecode)) { diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index 857ea7ec9..37a71f7bb 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -37,27 +37,26 @@ private slots: private: QFont font; - StringField* text_val; - DoubleField* size_val; - ColorField* set_color_button; - FontField* set_font_combobox; - ComboField* halign_field; - ComboField* valign_field; - BoolField* word_wrap_field; - DoubleField* padding_field; - DoubleField* position_x; - DoubleField* position_y; + StringInput* text_val; + DoubleInput* size_val; + ColorInput* set_color_button; + FontInput* set_font_combobox; + ComboInput* halign_field; + ComboInput* valign_field; + BoolInput* word_wrap_field; + DoubleInput* padding_field; + Vec2Input* position; - BoolField* outline_bool; - DoubleField* outline_width; - ColorField* outline_color; + BoolInput* outline_bool; + DoubleInput* outline_width; + ColorInput* outline_color; - BoolField* shadow_bool; - DoubleField* shadow_angle; - DoubleField* shadow_distance; - ColorField* shadow_color; - DoubleField* shadow_softness; - DoubleField* shadow_opacity; + BoolInput* shadow_bool; + DoubleInput* shadow_angle; + DoubleInput* shadow_distance; + ColorInput* shadow_color; + DoubleInput* shadow_softness; + DoubleInput* shadow_opacity; }; diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index 613b39383..3353057e3 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -47,43 +47,31 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : { SetFlags(Effect::SuperimposeFlag); - EffectRow* tc_row = new EffectRow(this, tr("Timecode")); - tc_select = new ComboField(tc_row, "tc_selector"); + tc_select = new ComboInput(this, "tc_selector", tr("Timecode")); tc_select->AddItem(tr("Sequence"), true); tc_select->AddItem(tr("Media"), false); tc_select->SetValueAt(0, true); - EffectRow* scale_row = new EffectRow(this, tr("Scale")); - scale_val = new DoubleField(scale_row, "scale"); - scale_val->SetColumnSpan(2); + scale_val = new DoubleInput(this, "scale", tr("Scale")); scale_val->SetMinimum(1); scale_val->SetDefault(100); scale_val->SetMaximum(1000); - EffectRow* color_row = new EffectRow(this, tr("Color")); - color_val = new ColorField(color_row, "color"); - color_val->SetColumnSpan(2); + color_val = new ColorInput(this, "color", tr("Color")); color_val->SetValueAt(0, QColor(Qt::white)); - EffectRow* color_bg_row = new EffectRow(this, tr("Background Color")); - color_bg_val = new ColorField(color_bg_row, "bgcolor"); - color_bg_val->SetColumnSpan(2); + color_bg_val = new ColorInput(this, "bgcolor", tr("Background Color")); color_bg_val->SetValueAt(0, QColor(Qt::black)); - EffectRow* bg_alpha_row = new EffectRow(this, tr("Background Opacity")); - bg_alpha = new DoubleField(bg_alpha_row, "bgalpha"); - bg_alpha->SetColumnSpan(2); + bg_alpha = new DoubleInput(this, "bgalpha", tr("Background Opacity")); bg_alpha->SetMinimum(0); bg_alpha->SetDefault(50); bg_alpha->SetMaximum(100); - EffectRow* offset_row = new EffectRow(this, tr("Offset")); - offset_x_val = new DoubleField(offset_row, "offsetx"); - offset_y_val = new DoubleField(offset_row, "offsety"); + offset_val = new Vec2Input(this, "offset", tr("Offset")); + offset_val->SetDefault(0); - EffectRow* prepent_text_row = new EffectRow(this, tr("Prepend")); - prepend_text = new StringField(prepent_text_row, "prepend", false); - prepend_text->SetColumnSpan(2); + prepend_text = new StringInput(this, "prepend", tr("Prepend"), false); } @@ -116,18 +104,17 @@ void TimecodeEffect::redraw(double timecode) { QPainterPath path; - int text_x, text_y, rect_y, offset_x, offset_y; + int text_x, text_y, rect_y; int text_height = fm.height(); int text_width = fm.width(display_timecode); QColor background_color = color_bg_val->GetColorAt(timecode); int alpha_val = qCeil(bg_alpha->GetDoubleAt(timecode)*2.55); background_color.setAlpha(alpha_val); - offset_x = int(offset_x_val->GetDoubleAt(timecode)); - offset_y = int(offset_y_val->GetDoubleAt(timecode)); + QVector2D offset = offset_val->GetVector2DAt(timecode); - text_x = offset_x + (width/2) - (text_width/2); - text_y = offset_y + height - height/10; + text_x = offset.x() + (width/2) - (text_width/2); + text_y = offset.y() + height - height/10; rect_y = text_y + fm.descent() - text_height; path.addText(text_x, text_y, font, display_timecode); diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h index 743796199..693452d06 100644 --- a/effects/internal/timecodeeffect.h +++ b/effects/internal/timecodeeffect.h @@ -31,14 +31,13 @@ class TimecodeEffect : public Effect { public: TimecodeEffect(Clip* c, const EffectMeta *em); virtual void redraw(double timecode) override; - DoubleField* scale_val; - ColorField* color_val; - ColorField* color_bg_val; - DoubleField* bg_alpha; - DoubleField* offset_x_val; - DoubleField* offset_y_val; - StringField* prepend_text; - ComboField* tc_select; + DoubleInput* scale_val; + ColorInput* color_val; + ColorInput* color_bg_val; + DoubleInput* bg_alpha; + Vec2Input* offset_val; + StringInput* prepend_text; + ComboInput* tc_select; protected: virtual bool AlwaysUpdate() override; diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index 914d8ef78..c207f76bb 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -28,24 +28,20 @@ #include "timeline/sequence.h" ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { - EffectRow* type_row = new EffectRow(this, tr("Type")); - type_val = new ComboField(type_row, "type"); + type_val = new ComboInput(this, "type", tr("Type")); type_val->AddItem(tr("Sine"), TONE_TYPE_SINE); - EffectRow* frequency_row = new EffectRow(this, tr("Frequency")); - freq_val = new DoubleField(frequency_row, "frequency"); + freq_val = new DoubleInput(this, "frequency", tr("Frequency")); freq_val->SetMinimum(20); freq_val->SetMaximum(20000); freq_val->SetDefault(1000); - EffectRow* amount_row = new EffectRow(this, tr("Amount")); - amount_val = new DoubleField(amount_row, "amount"); + amount_val = new DoubleInput(this, "amount", tr("Amount")); amount_val->SetMinimum(0); amount_val->SetMaximum(100); amount_val->SetDefault(25); - EffectRow* mix_row = new EffectRow(this, tr("Mix")); - mix_val = new BoolField(mix_row, "mix"); + mix_val = new BoolInput(this, "mix", tr("Mix")); mix_val->SetValueAt(0, true); } diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h index 396bb5806..4420fbbb1 100644 --- a/effects/internal/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -34,10 +34,10 @@ public: int channel_count, int type) override; - ComboField* type_val; - DoubleField* freq_val; - DoubleField* amount_val; - BoolField* mix_val; + ComboInput* type_val; + DoubleInput* freq_val; + DoubleInput* amount_val; + BoolInput* mix_val; private: int sinX; }; diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 425c00bae..c48ec341d 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -46,116 +46,86 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); - EffectRow* position_row = new EffectRow(this, tr("Position")); + position = new Vec2Input(this, "pos", tr("Position")); - position_x = new DoubleField(position_row, "posx"); // position X - position_y = new DoubleField(position_row, "posy"); // position Y + scale = new Vec2Input(this, "scale", tr("Scale")); + scale->SetMinimum(0); + scale->SetDefault(100); - EffectRow* scale_row = new EffectRow(this, tr("Scale")); + uniform_scale_field = new BoolInput(this, "uniformscale", tr("Uniform Scale")); + connect(uniform_scale_field, SIGNAL(Toggled(bool)), scale, SLOT(SetSingleValueMode(bool))); + uniform_scale_field->SetValueAt(0, true); - // scale X (and Y is uniform scale is selected) - scale_x = new DoubleField(scale_row, "scalex"); - scale_x->SetMinimum(0); + rotation = new DoubleInput(this, "rotation", tr("Rotation")); - // scale Y (disabled if uniform scale is selected) - scale_y = new DoubleField(scale_row, "scaley"); - scale_y->SetMinimum(0); - - EffectRow* uniform_scale_row = new EffectRow(this, tr("Uniform Scale")); - - uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option - - EffectRow* rotation_row = new EffectRow(this, tr("Rotation")); - - rotation = new DoubleField(rotation_row, "rotation"); - - EffectRow* anchor_point_row = new EffectRow(this, tr("Anchor Point")); - - anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X - anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y - - EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); + anchor_point = new Vec2Input(this, "anchor", tr("Anchor Point")); + anchor_point->SetDefault(0); // opacity - opacity = new DoubleField(opacity_row, "opacity"); + opacity = new DoubleInput(this, "opacity", tr("Opacity")); opacity->SetMinimum(0); opacity->SetMaximum(100); - - EffectRow* blend_mode_row = new EffectRow(this, tr("Blend Mode")); - - // blend mode - blend_mode_box = new ComboField(blend_mode_row, "blendmode"); - blend_mode_box->SetColumnSpan(2); - blend_mode_box->AddItem(tr("Normal"), -1); + opacity->SetDefault(100); // set up gizmos top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); - top_left_gizmo->x_field1 = scale_x; + top_left_gizmo->x_field1 = static_cast(scale->Field(0)); top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_center_gizmo->set_cursor(Qt::SizeVerCursor); - top_center_gizmo->y_field1 = scale_x; + top_center_gizmo->y_field1 = static_cast(scale->Field(0)); top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); - top_right_gizmo->x_field1 = scale_x; + top_right_gizmo->x_field1 = static_cast(scale->Field(0)); bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); - bottom_left_gizmo->x_field1 = scale_x; + bottom_left_gizmo->x_field1 = static_cast(scale->Field(0)); bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); - bottom_center_gizmo->y_field1 = scale_x; + bottom_center_gizmo->y_field1 = static_cast(scale->Field(0)); bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); - bottom_right_gizmo->x_field1 = scale_x; + bottom_right_gizmo->x_field1 = static_cast(scale->Field(0)); left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); left_center_gizmo->set_cursor(Qt::SizeHorCursor); - left_center_gizmo->x_field1 = scale_x; + left_center_gizmo->x_field1 = static_cast(scale->Field(0)); right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); right_center_gizmo->set_cursor(Qt::SizeHorCursor); - right_center_gizmo->x_field1 = scale_x; + right_center_gizmo->x_field1 = static_cast(scale->Field(0)); anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET); anchor_gizmo->set_cursor(Qt::SizeAllCursor); - anchor_gizmo->x_field1 = anchor_x_box; - anchor_gizmo->y_field1 = anchor_y_box; - anchor_gizmo->x_field2 = position_x; - anchor_gizmo->y_field2 = position_y; + anchor_gizmo->x_field1 = static_cast(anchor_point->Field(0)); + anchor_gizmo->y_field1 = static_cast(anchor_point->Field(1)); + anchor_gizmo->x_field2 = static_cast(position->Field(0)); + anchor_gizmo->y_field2 = static_cast(position->Field(1)); rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); rotate_gizmo->color = Qt::green; rotate_gizmo->set_cursor(Qt::SizeAllCursor); - rotate_gizmo->x_field1 = rotation; + rotate_gizmo->x_field1 = static_cast(rotation->Field(0)); rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); - rect_gizmo->x_field1 = position_x; - rect_gizmo->y_field1 = position_y; + rect_gizmo->x_field1 = static_cast(position->Field(0)); + rect_gizmo->y_field1 = static_cast(position->Field(1)); connect(uniform_scale_field, SIGNAL(Toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); - // set defaults - uniform_scale_field->SetValueAt(0, true); - blend_mode_box->SetValueAt(0, -1); - anchor_x_box->SetDefault(0); - anchor_y_box->SetDefault(0); - opacity->SetDefault(100); - scale_x->SetDefault(100); - scale_y->SetDefault(100); - refresh(); } void TransformEffect::refresh() { if (parent_clip != nullptr && parent_clip->track()->sequence() != nullptr) { - position_x->SetDefault(parent_clip->track()->sequence()->width/2); - position_y->SetDefault(parent_clip->track()->sequence()->height/2); + position->SetDefault({float(parent_clip->track()->sequence()->width)*0.5f, + float(parent_clip->track()->sequence()->height)*0.5f}); double x_percent_multipler = 200.0 / parent_clip->track()->sequence()->width; double y_percent_multipler = 200.0 / parent_clip->track()->sequence()->height; @@ -178,7 +148,10 @@ void TransformEffect::refresh() { } void TransformEffect::toggle_uniform_scale(bool enabled) { - scale_y->SetEnabled(!enabled); + scale->SetSingleValueMode(enabled); + + DoubleField* scale_x = static_cast(scale->Field(0)); + DoubleField* scale_y = static_cast(scale->Field(1)); top_center_gizmo->y_field1 = enabled ? scale_x : scale_y; bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y; @@ -190,29 +163,23 @@ void TransformEffect::toggle_uniform_scale(bool enabled) { void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { // position - coords.matrix.translate(position_x->GetDoubleAt(timecode)-(parent_clip->track()->sequence()->width/2), - position_y->GetDoubleAt(timecode)-(parent_clip->track()->sequence()->height/2), - 0); + coords.matrix.translate(position->GetVector2DAt(timecode) + - QVector2D(parent_clip->track()->sequence()->width*0.5f, + parent_clip->track()->sequence()->height*0.5f)); // anchor point - int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); - int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode)); + QVector2D anchor_val = anchor_point->GetVector2DAt(timecode); - coords.vertex_top_left -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); - coords.vertex_top_right -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); - coords.vertex_bottom_left -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); - coords.vertex_bottom_right -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); + coords.vertex_top_left -= anchor_val; + coords.vertex_top_right -= anchor_val; + coords.vertex_bottom_left -= anchor_val; + coords.vertex_bottom_right -= anchor_val; // rotation coords.matrix.rotate(QQuaternion::fromEulerAngles(0, 0, rotation->GetDoubleAt(timecode))); // scale - double sx = scale_x->GetDoubleAt(timecode)*0.01; - double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01; - coords.matrix.scale(sx, sy); - - // blend mode - coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt(); + coords.matrix.scale(scale->GetVector2DAt(timecode)*0.01); // opacity coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01); @@ -239,9 +206,9 @@ void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { rotate_gizmo->world_pos[0] = QVector3D( float_lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), 0.5f), - float_lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1f), - 0.0f - ); + float_lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1f), + 0.0f + ); rect_gizmo->world_pos[0] = coords.vertex_top_left; rect_gizmo->world_pos[1] = coords.vertex_top_right; diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h index 42c840559..19c856c28 100644 --- a/effects/internal/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -31,19 +31,17 @@ public: virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override; virtual void gizmo_draw(double timecode, GLTextureCoords& coords) override; + public slots: void toggle_uniform_scale(bool enabled); + private: - DoubleField* position_x; - DoubleField* position_y; - DoubleField* scale_x; - DoubleField* scale_y; - BoolField* uniform_scale_field; - DoubleField* rotation; - DoubleField* anchor_x_box; - DoubleField* anchor_y_box; - DoubleField* opacity; - ComboField* blend_mode_box; + Vec2Input* position; + Vec2Input* scale; + BoolInput* uniform_scale_field; + DoubleInput* rotation; + Vec2Input* anchor_point; + DoubleInput* opacity; EffectGizmo* top_left_gizmo; EffectGizmo* top_center_gizmo; diff --git a/effects/internal/voideffect.cpp b/effects/internal/voideffect.cpp index 435d32e94..a82aaffdd 100644 --- a/effects/internal/voideffect.cpp +++ b/effects/internal/voideffect.cpp @@ -34,9 +34,8 @@ VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) { } else { display_name = n; } - EffectRow* row = new EffectRow(this, tr("Missing Effect"), false, false); - new LabelField(row, display_name); + new LabelWidget(this, tr("Missing Effect"), display_name); name = display_name; diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index 102b02b90..c400ff89b 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -29,8 +29,7 @@ #include "ui/collapsiblewidget.h" VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* volume_row = new EffectRow(this, tr("Volume")); - volume_val = new DoubleField(volume_row, "volume"); + volume_val = new DoubleInput(this, "volume", tr("Volume")); // set defaults volume_val->SetDefault(1); diff --git a/effects/internal/volumeeffect.h b/effects/internal/volumeeffect.h index c4a7a6180..19c855217 100644 --- a/effects/internal/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -34,7 +34,7 @@ public: int channel_count, int type) override; - DoubleField* volume_val; + DoubleInput* volume_val; }; #endif // VOLUMEEFFECT_H diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index bbde8503a..954f658c0 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -236,13 +236,10 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : { plugin = nullptr; - EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false); - file_field = new FileField(file_row, "filename"); + file_field = new FileInput(this, "filename", tr("Plugin"), true, false); connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()), Qt::QueuedConnection); - EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false); - - show_interface_btn = new ButtonField(interface_row, tr("Show")); + show_interface_btn = new ButtonWidget(this, tr("Interface"), tr("Show")); show_interface_btn->SetCheckable(true); show_interface_btn->SetEnabled(false); connect(show_interface_btn, SIGNAL(Toggled(bool)), this, SLOT(show_interface(bool))); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index f934750d8..301d2ef89 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -65,8 +65,8 @@ private slots: void uncheck_show_button(); void change_plugin(); private: - FileField* file_field; - ButtonField* show_interface_btn; + FileInput* file_field; + ButtonWidget* show_interface_btn; void loadPlugin(); void freePlugin(); diff --git a/effects/shaders/boxblur.xml b/effects/shaders/boxblur.xml index 59bf40ca2..b430794c9 100644 --- a/effects/shaders/boxblur.xml +++ b/effects/shaders/boxblur.xml @@ -1,13 +1,7 @@ - - - - - - - - - + + + \ No newline at end of file diff --git a/effects/transition.cpp b/effects/transition.cpp index 469aa59dd..5c1809d97 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -44,8 +44,7 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : Effect(c, em), secondary_clip(s) { - EffectRow* length_row = new EffectRow(this, tr("Length"), false, false); - length_field = new DoubleField(length_row, "length"); + length_field = new DoubleInput(this, "length", tr("Length"), false, false); length_field->SetDefault(30); length_field->SetMinimum(1); length_field->SetDisplayType(LabelSlider::FrameNumber); diff --git a/effects/transition.h b/effects/transition.h index 01a47cd8b..20adde1ba 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -61,7 +61,7 @@ public: static TransitionPtr CreateFromMeta(Clip *c, Clip *s, const EffectMeta* em); private: - DoubleField* length_field; + DoubleInput* length_field; private slots: void UpdateMaximumLength(); diff --git a/nodes/inputs.h b/nodes/inputs.h new file mode 100644 index 000000000..796cbaffb --- /dev/null +++ b/nodes/inputs.h @@ -0,0 +1,15 @@ +#ifndef INPUTS_H +#define INPUTS_H + +#include "inputs/vecinput.h" +#include "inputs/boolinput.h" +#include "inputs/comboinput.h" +#include "inputs/colorinput.h" +#include "inputs/stringinput.h" +#include "inputs/fileinput.h" +#include "inputs/fontinput.h" + +#include "widgets/labelwidget.h" +#include "widgets/buttonwidget.h" + +#endif // INPUTS_H diff --git a/nodes/inputs/boolinput.cpp b/nodes/inputs/boolinput.cpp new file mode 100644 index 000000000..7ae067ed0 --- /dev/null +++ b/nodes/inputs/boolinput.cpp @@ -0,0 +1,14 @@ +#include "boolinput.h" + +BoolInput::BoolInput(Effect* parent, const QString& id, const QString& name, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + BoolField* bool_field = new BoolField(this); + connect(bool_field, SIGNAL(Toggled(bool)), this, SIGNAL(Toggled(bool))); + AddField(bool_field); +} + +bool BoolInput::GetBoolAt(double timecode) +{ + return static_cast(Field(0))->GetBoolAt(timecode); +} diff --git a/nodes/inputs/boolinput.h b/nodes/inputs/boolinput.h new file mode 100644 index 000000000..d04c89a6f --- /dev/null +++ b/nodes/inputs/boolinput.h @@ -0,0 +1,36 @@ +#ifndef BOOLINPUT_H +#define BOOLINPUT_H + +#include "effects/effectrow.h" + +class BoolInput : public EffectRow +{ + Q_OBJECT +public: + BoolInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + /** + * @brief Get the boolean value at a given timecode + * + * A wrapper for BoolField::GetBoolAt(). + * + * @param timecode + * + * The timecode to retrieve the value at + * + * @return + * + * The boolean value at this timecode + */ + bool GetBoolAt(double timecode); + +signals: + /** + * @brief Emitted whenever the UI widget's boolean value has changed + * + * Wrapper for BoolField::Toggled(). + */ + void Toggled(bool); +}; + +#endif // BOOLINPUT_H diff --git a/nodes/inputs/colorinput.cpp b/nodes/inputs/colorinput.cpp new file mode 100644 index 000000000..eab5010f4 --- /dev/null +++ b/nodes/inputs/colorinput.cpp @@ -0,0 +1,12 @@ +#include "colorinput.h" + +ColorInput::ColorInput(Effect* parent, const QString& id, const QString& name, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + AddField(new ColorField(this)); +} + +QColor ColorInput::GetColorAt(double timecode) +{ + static_cast(Field(0))->GetColorAt(timecode); +} diff --git a/nodes/inputs/colorinput.h b/nodes/inputs/colorinput.h new file mode 100644 index 000000000..d46acfd38 --- /dev/null +++ b/nodes/inputs/colorinput.h @@ -0,0 +1,28 @@ +#ifndef COLORINPUT_H +#define COLORINPUT_H + +#include "effects/effectrow.h" + +class ColorInput : public EffectRow +{ + Q_OBJECT +public: + ColorInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + /** + * @brief Get the color value at a given timecode + * + * Wrapper for ColorField::GetColorAt(). + * + * @param timecode + * + * The timecode to retrieve the color at + * + * @return + * + * The color value at this timecode + */ + QColor GetColorAt(double timecode); +}; + +#endif // COLORINPUT_H diff --git a/nodes/inputs/comboinput.cpp b/nodes/inputs/comboinput.cpp new file mode 100644 index 000000000..aadeeef41 --- /dev/null +++ b/nodes/inputs/comboinput.cpp @@ -0,0 +1,14 @@ +#include "comboinput.h" + +ComboInput::ComboInput(Effect* parent, const QString& id, const QString& name, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + ComboField* combo_field = new ComboField(this); + connect(combo_field, SIGNAL(DataChanged(const QVariant&)), this, SIGNAL(DataChanged(const QVariant&))); + AddField(combo_field); +} + +void ComboInput::AddItem(const QString &text, const QVariant &data) +{ + static_cast(Field(0))->AddItem(text, data); +} diff --git a/nodes/inputs/comboinput.h b/nodes/inputs/comboinput.h new file mode 100644 index 000000000..d48eae16d --- /dev/null +++ b/nodes/inputs/comboinput.h @@ -0,0 +1,36 @@ +#ifndef COMBOINPUT_H +#define COMBOINPUT_H + +#include "effects/effectrow.h" + +class ComboInput : public EffectRow +{ + Q_OBJECT +public: + ComboInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + /** + * @brief Add an item to this ComboInput + * + * Wrapper for ComboField::AddItem. + * + * @param text + * + * The text to show at this index. + * + * @param data + * + * The data to be retrieved at this index. + */ + void AddItem(const QString& text, const QVariant& data); + +signals: + /** + * @brief Signal emitted whenever a connected widget's data gets changed + * + * Wrapper for ComboField::DataChanged. + */ + void DataChanged(const QVariant&); +}; + +#endif // COMBOINPUT_H diff --git a/nodes/inputs/doubleinput.cpp b/nodes/inputs/doubleinput.cpp deleted file mode 100644 index dded84c1f..000000000 --- a/nodes/inputs/doubleinput.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "doubleinput.h" - -DoubleInput::DoubleInput() -{ - -} diff --git a/nodes/inputs/doubleinput.h b/nodes/inputs/doubleinput.h deleted file mode 100644 index 58e468496..000000000 --- a/nodes/inputs/doubleinput.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DOUBLEINPUT_H -#define DOUBLEINPUT_H - -#include "effects/effectrow.h" - -class DoubleInput : public EffectRow -{ -public: - DoubleInput(); -}; - -#endif // DOUBLEINPUT_H diff --git a/nodes/inputs/fileinput.cpp b/nodes/inputs/fileinput.cpp new file mode 100644 index 000000000..011506747 --- /dev/null +++ b/nodes/inputs/fileinput.cpp @@ -0,0 +1,12 @@ +#include "fileinput.h" + +FileInput::FileInput(Effect* parent, const QString& id, const QString& name, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + AddField(new FileField(this)); +} + +QString FileInput::GetFileAt(double timecode) +{ + return static_cast(Field(0))->GetFileAt(timecode); +} diff --git a/nodes/inputs/fileinput.h b/nodes/inputs/fileinput.h new file mode 100644 index 000000000..9473a9c13 --- /dev/null +++ b/nodes/inputs/fileinput.h @@ -0,0 +1,28 @@ +#ifndef FILEINPUT_H +#define FILEINPUT_H + +#include "effects/effectrow.h" + +class FileInput : public EffectRow +{ + Q_OBJECT +public: + FileInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + /** + * @brief Get the filename at the given timecode + * + * A convenience function, equivalent to GetValueAt(timecode).toString() + * + * @param timecode + * + * The timecode to retrieve the filename at + * + * @return + * + * The filename at this timecode + */ + QString GetFileAt(double timecode); +}; + +#endif // FILEINPUT_H diff --git a/nodes/inputs/fontinput.cpp b/nodes/inputs/fontinput.cpp new file mode 100644 index 000000000..3e0041136 --- /dev/null +++ b/nodes/inputs/fontinput.cpp @@ -0,0 +1,12 @@ +#include "fontinput.h" + +FontInput::FontInput(Effect* parent, const QString& id, const QString& name, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + AddField(new FontField(this)); +} + +QString FontInput::GetFontAt(double timecode) +{ + return static_cast(Field(0))->GetFontAt(timecode); +} diff --git a/nodes/inputs/fontinput.h b/nodes/inputs/fontinput.h new file mode 100644 index 000000000..b1ac07979 --- /dev/null +++ b/nodes/inputs/fontinput.h @@ -0,0 +1,28 @@ +#ifndef FONTINPUT_H +#define FONTINPUT_H + +#include "effects/effectrow.h" + +class FontInput : public EffectRow +{ + Q_OBJECT +public: + FontInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + /** + * @brief Get the font family name at the given timecode + * + * Wrapper for FontField::GetFontAt(). + * + * @param timecode + * + * The timecode to retrieve the font family name at + * + * @return + * + * The font family name at this timecode + */ + QString GetFontAt(double timecode); +}; + +#endif // FONTINPUT_H diff --git a/nodes/inputs/stringinput.cpp b/nodes/inputs/stringinput.cpp new file mode 100644 index 000000000..0169c3826 --- /dev/null +++ b/nodes/inputs/stringinput.cpp @@ -0,0 +1,12 @@ +#include "stringinput.h" + +StringInput::StringInput(Effect* parent, const QString& id, const QString& name, bool rich_text, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable) +{ + AddField(new StringField(this, rich_text)); +} + +QString StringInput::GetStringAt(double timecode) +{ + return static_cast(Field(0))->GetStringAt(timecode); +} diff --git a/nodes/inputs/stringinput.h b/nodes/inputs/stringinput.h new file mode 100644 index 000000000..4498bbae9 --- /dev/null +++ b/nodes/inputs/stringinput.h @@ -0,0 +1,33 @@ +#ifndef STRINGINPUT_H +#define STRINGINPUT_H + +#include "effects/effectrow.h" + +class StringInput : public EffectRow +{ + Q_OBJECT +public: + StringInput(Effect* parent, + const QString& id, + const QString& name, + bool rich_text = true, + bool savable = true, + bool keyframable = true); + + /** + * @brief Get the string at the given timecode + * + * Wrappre for StringField::GetStringAt(). + * + * @param timecode + * + * The timecode to retrieve the string at + * + * @return + * + * The string at this timecode + */ + QString GetStringAt(double timecode); +}; + +#endif // STRINGINPUT_H diff --git a/nodes/inputs/vecinput.cpp b/nodes/inputs/vecinput.cpp new file mode 100644 index 000000000..82e74ea60 --- /dev/null +++ b/nodes/inputs/vecinput.cpp @@ -0,0 +1,186 @@ +#include "vecinput.h" + +#include +#include +#include + +VecInput::VecInput(Effect* parent, const QString& id, const QString& name, int values, bool savable, bool keyframable) : + EffectRow(parent, id, name, savable, keyframable), + single_value_mode_(false), + values_(values) +{ + Q_ASSERT(values_ >= 1 && values_ <= 4); + + for (int i=0;i(Field(i))->SetMinimum(minimum); + } +} + +void VecInput::SetMaximum(double maximum) +{ + for (int i=0;i(Field(i))->SetMaximum(maximum); + } +} + +void VecInput::SetDefault(double def) +{ + for (int i=0;i(Field(i))->SetDefault(def); + } +} + +void VecInput::SetDefault(const QVector &def) +{ + for (int i=0;i(Field(i))->SetDefault(def.at(i)); + } +} + +void VecInput::SetDisplayType(LabelSlider::DisplayType type) +{ + for (int i=0;i(Field(i))->SetDisplayType(type); + } +} + +void VecInput::SetFrameRate(const double &rate) +{ + for (int i=0;i(Field(i))->SetFrameRate(rate); + } +} + +void VecInput::SetSingleValueMode(bool on) +{ + qDebug() << "i'm here"; + + single_value_mode_ = on; + + // Disable all fields except the first + for (int i=1;iSetEnabled(!single_value_mode_); + } +} + +DoubleInput::DoubleInput(Effect *parent, const QString &id, const QString &name, bool savable, bool keyframable) : + VecInput(parent, id, name, 1, savable, keyframable) +{ +} + +double DoubleInput::GetDoubleAt(double timecode) +{ + return static_cast(Field(0))->GetDoubleAt(timecode); +} + +Vec2Input::Vec2Input(Effect *parent, const QString &id, const QString &name, bool savable, bool keyframable) : + VecInput(parent, id, name, 2, savable, keyframable) +{ +} + +QVector2D Vec2Input::GetVector2DAt(double timecode) +{ + return GetValueAt(timecode).value(); +} + +QVariant Vec2Input::GetValueAt(double timecode) +{ + QVector2D vec2; + vec2.setX(static_cast(Field(0))->GetDoubleAt(timecode)); + + if (single_value_mode_) { + vec2.setY(static_cast(Field(0))->GetDoubleAt(timecode)); + } else { + vec2.setY(static_cast(Field(1))->GetDoubleAt(timecode)); + } + + return vec2; +} + +void Vec2Input::SetValueAt(double timecode, const QVariant &value) +{ + QVector2D vec2 = value.value(); + + static_cast(Field(0))->SetValueAt(timecode, vec2.x()); + static_cast(Field(1))->SetValueAt(timecode, vec2.y()); +} + +Vec3Input::Vec3Input(Effect *parent, const QString &id, const QString &name, bool savable, bool keyframable) : + VecInput(parent, id, name, 3, savable, keyframable) +{ +} + +QVector3D Vec3Input::GetVector3DAt(double timecode) +{ + return GetValueAt(timecode).value(); +} + +QVariant Vec3Input::GetValueAt(double timecode) +{ + QVector3D vec3; + vec3.setX(static_cast(Field(0))->GetDoubleAt(timecode)); + + if (single_value_mode_) { + vec3.setY(static_cast(Field(0))->GetDoubleAt(timecode)); + vec3.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); + } else { + vec3.setY(static_cast(Field(1))->GetDoubleAt(timecode)); + vec3.setZ(static_cast(Field(2))->GetDoubleAt(timecode)); + } + + return vec3; +} + +void Vec3Input::SetValueAt(double timecode, const QVariant &value) +{ + QVector3D vec3 = value.value(); + + static_cast(Field(0))->SetValueAt(timecode, vec3.x()); + static_cast(Field(1))->SetValueAt(timecode, vec3.y()); + static_cast(Field(2))->SetValueAt(timecode, vec3.z()); +} + +Vec4Input::Vec4Input(Effect *parent, const QString &id, const QString &name, bool savable, bool keyframable) : + VecInput(parent, id, name, 4, savable, keyframable) +{ +} + +QVector4D Vec4Input::GetVector4DAt(double timecode) +{ + return GetValueAt(timecode).value(); +} + +QVariant Vec4Input::GetValueAt(double timecode) +{ + QVector4D vec4; + vec4.setX(static_cast(Field(0))->GetDoubleAt(timecode)); + + if (single_value_mode_) { + vec4.setY(static_cast(Field(0))->GetDoubleAt(timecode)); + vec4.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); + vec4.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); + } else { + vec4.setY(static_cast(Field(1))->GetDoubleAt(timecode)); + vec4.setZ(static_cast(Field(2))->GetDoubleAt(timecode)); + vec4.setW(static_cast(Field(3))->GetDoubleAt(timecode)); + } + + return vec4; +} + +void Vec4Input::SetValueAt(double timecode, const QVariant &value) +{ + QVector4D vec4 = value.value(); + + static_cast(Field(0))->SetValueAt(timecode, vec4.x()); + static_cast(Field(1))->SetValueAt(timecode, vec4.y()); + static_cast(Field(2))->SetValueAt(timecode, vec4.z()); + static_cast(Field(3))->SetValueAt(timecode, vec4.w()); +} diff --git a/nodes/inputs/vecinput.h b/nodes/inputs/vecinput.h new file mode 100644 index 000000000..9698308d1 --- /dev/null +++ b/nodes/inputs/vecinput.h @@ -0,0 +1,78 @@ +#ifndef VEC2INPUT_H +#define VEC2INPUT_H + +#include + +#include "effects/effectrow.h" + +class VecInput : public EffectRow +{ + Q_OBJECT +public: + VecInput(Effect* parent, const QString& id, const QString& name, int values, bool savable = true, bool keyframable = true); + + void SetMinimum(double minimum); + void SetMaximum(double maximum); + void SetDefault(double def); + + void SetDefault(const QVector &def); + + /** + * @brief Sets the UI display type to a member of LabelSlider::DisplayType. + */ + void SetDisplayType(LabelSlider::DisplayType type); + + /** + * @brief For a timecode-based display type, sets the frame rate to be used for the displayed timecode + * + * \see SetDisplayType() and LabelSlider::SetFrameRate(). + */ + void SetFrameRate(const double& rate); + +protected: + bool single_value_mode_; + +public slots: + void SetSingleValueMode(bool on); + +private: + + int values_; +}; + +class DoubleInput : public VecInput +{ +public: + DoubleInput(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + double GetDoubleAt(double timecode); +}; + +class Vec2Input : public VecInput { +public: + Vec2Input(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + QVector2D GetVector2DAt(double timecode); + virtual QVariant GetValueAt(double timecode) override; + virtual void SetValueAt(double timecode, const QVariant &value) override; +}; + +class Vec3Input : public VecInput { +public: + Vec3Input(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + QVector3D GetVector3DAt(double timecode); + virtual QVariant GetValueAt(double timecode) override; + virtual void SetValueAt(double timecode, const QVariant &value) override; +}; + +class Vec4Input : public VecInput { +public: + Vec4Input(Effect* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); + + QVector4D GetVector4DAt(double timecode); + virtual QVariant GetValueAt(double timecode) override; + virtual void SetValueAt(double timecode, const QVariant &value) override; +}; + +#endif // VEC2INPUT_H diff --git a/nodes/nodedatatypes.h b/nodes/nodedatatypes.h index ebf20eadf..3250457e4 100644 --- a/nodes/nodedatatypes.h +++ b/nodes/nodedatatypes.h @@ -12,13 +12,13 @@ namespace nodes { * Predetermined types of fields. Used throughout Olive to identify what kind of data to expect from GetValueAt(). * * This enum is also currently used to match an external XML effect's fields with the correct derived class (e.g. - * EFFECT_FIELD_DOUBLE matches to DoubleField). + * EFFECT_FIELD_DOUBLE matches to DoubleInput). */ enum DataType { /** Invalid data type. Used only for error handling. */ kInvalid, - /** Values are doubles. Also corresponds to DoubleField. */ + /** Values are doubles. Also corresponds to DoubleInput. */ kFloat, /** Value is an 2-component vector of floats. */ @@ -33,22 +33,22 @@ enum DataType { /** Value is an array of floats. This cannot be an input field, and can only be passed between nodes. */ kArray, - /** Values are colors. Equivalent to kVec4 but represents as a color. Corresponds to ColorField. */ + /** Values are colors. Equivalent to kVec4 but represents as a color. Corresponds to ColorInput. */ kColor, - /** Values are strings. Also corresponds to StringField. */ + /** Values are strings. Also corresponds to StringInput. */ kString, - /** Values are booleans. Also corresponds to BoolField. */ + /** Values are booleans. Also corresponds to BoolInput. */ kBoolean, - /** Values are arbitrary data. Also corresponds to ComboField. */ + /** Values are arbitrary data. Also corresponds to ComboInput. */ kCombo, - /** Values are font family names (in string). Also corresponds to FontField. */ + /** Values are font family names (in string). Also corresponds to FontInput. */ kFont, - /** Values are filenames (in string). Also corresponds to FileField. */ + /** Values are filenames (in string). Also corresponds to FileInput. */ kFile, /** Values are integers. */ diff --git a/nodes/widgets/buttonwidget.cpp b/nodes/widgets/buttonwidget.cpp new file mode 100644 index 000000000..bde083736 --- /dev/null +++ b/nodes/widgets/buttonwidget.cpp @@ -0,0 +1,23 @@ +#include "buttonwidget.h" + +ButtonWidget::ButtonWidget(Effect* parent, const QString& name, const QString& text) : + EffectRow(parent, nullptr, name, false, false) +{ + ButtonField* button_field = new ButtonField(this, text); + + connect(button_field, SIGNAL(CheckedChanged(bool)), this, SIGNAL(CheckedChanged(bool))); + connect(button_field, SIGNAL(Toggled(bool)), this, SIGNAL(Toggled(bool))); + connect(this, SLOT(SetChecked(bool)), button_field, SLOT(SetChecked(bool))); + + AddField(button_field); +} + +void ButtonWidget::SetCheckable(bool c) +{ + static_cast(Field(0))->SetCheckable(c); +} + +void ButtonWidget::SetChecked(bool c) +{ + static_cast(Field(0))->SetChecked(c); +} diff --git a/nodes/widgets/buttonwidget.h b/nodes/widgets/buttonwidget.h new file mode 100644 index 000000000..e7e068f24 --- /dev/null +++ b/nodes/widgets/buttonwidget.h @@ -0,0 +1,35 @@ +#ifndef BUTTONWIDGET_H +#define BUTTONWIDGET_H + +#include "effects/effectrow.h" + +class ButtonWidget : public EffectRow +{ +public: + ButtonWidget(Effect* parent, const QString& name, const QString& text); + + /** + * @brief Wrapper for ButtonField::SetCheckable. + */ + void SetCheckable(bool c); + +public slots: + /** + * @brief Wrapper for ButtonField::SetChecked() + */ + void SetChecked(bool c); + +signals: + /** + * @brief Wrapper for ButtonField::CheckedChanged() + */ + void CheckedChanged(bool); + + /** + * @brief Wrapper for ButtonField::Toggled() + */ + void Toggled(bool); + +}; + +#endif // BUTTONWIDGET_H diff --git a/nodes/widgets/labelwidget.cpp b/nodes/widgets/labelwidget.cpp new file mode 100644 index 000000000..02396436c --- /dev/null +++ b/nodes/widgets/labelwidget.cpp @@ -0,0 +1,7 @@ +#include "labelwidget.h" + +LabelWidget::LabelWidget(Effect *parent, const QString &name, const QString &text) : + EffectRow(parent, nullptr, name, false, false) +{ + AddField(new LabelField(this, text)); +} diff --git a/nodes/widgets/labelwidget.h b/nodes/widgets/labelwidget.h new file mode 100644 index 000000000..af066f9a4 --- /dev/null +++ b/nodes/widgets/labelwidget.h @@ -0,0 +1,12 @@ +#ifndef LABELWIDGET_H +#define LABELWIDGET_H + +#include "effects/effectrow.h" + +class LabelWidget : public EffectRow +{ +public: + LabelWidget(Effect* parent, const QString& name, const QString& text); +}; + +#endif // LABELWIDGET_H diff --git a/olive.pro b/olive.pro index d9d2f8f17..2c7cb1043 100644 --- a/olive.pro +++ b/olive.pro @@ -194,7 +194,15 @@ SOURCES += \ panels/effectspanel.cpp \ nodes/nodedatatypes.cpp \ nodes/nodeplug.cpp \ - nodes/inputs/doubleinput.cpp + nodes/inputs/boolinput.cpp \ + nodes/inputs/comboinput.cpp \ + nodes/inputs/colorinput.cpp \ + nodes/inputs/stringinput.cpp \ + nodes/inputs/fontinput.cpp \ + nodes/inputs/vecinput.cpp \ + nodes/widgets/labelwidget.cpp \ + nodes/inputs/fileinput.cpp \ + nodes/widgets/buttonwidget.cpp HEADERS += \ ui/mainwindow.h \ @@ -343,7 +351,16 @@ HEADERS += \ panels/effectspanel.h \ nodes/nodedatatypes.h \ nodes/nodeplug.h \ - nodes/inputs/doubleinput.h + nodes/inputs.h \ + nodes/inputs/boolinput.h \ + nodes/inputs/comboinput.h \ + nodes/inputs/colorinput.h \ + nodes/inputs/stringinput.h \ + nodes/inputs/fontinput.h \ + nodes/inputs/vecinput.h \ + nodes/widgets/labelwidget.h \ + nodes/inputs/fileinput.h \ + nodes/widgets/buttonwidget.h FORMS += diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index 6430a80fd..370a0cb09 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -149,8 +149,8 @@ void GraphEditor::update_panel() { int slider_index = 0; for (int i=0;iFieldCount();i++) { EffectField* field = row->Field(i); - if (field->type() == olive::nodes::kFloat) { - field->UpdateWidgetValue(field_sliders_.at(slider_index), field->Now()); + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { + field->UpdateWidgetValue(field_sliders_.at(slider_index), row->GetParentEffect()->Now()); slider_index++; } } @@ -186,7 +186,7 @@ void GraphEditor::set_row(EffectRow *r) { if (r != nullptr && r->IsKeyframing()) { for (int i=0;iFieldCount();i++) { EffectField* field = r->Field(i); - if (field->type() == olive::nodes::kFloat) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { QPushButton* slider_button = new QPushButton(); slider_button->setCheckable(true); slider_button->setChecked(field->IsEnabled()); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index c0b3f7a0a..bc3b8774a 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -260,6 +260,13 @@ void Timeline::toggle_show_all() { } } +void Timeline::toggle_links() +{ + if (sequence_ != nullptr) { + sequence_->ToggleLinksOnSelected(); + } +} + void Timeline::add_transition() { ComboAction* ca = new ComboAction(); bool adding = false; diff --git a/panels/timeline.h b/panels/timeline.h index b838e7d09..0606aef06 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -150,6 +150,7 @@ protected: public slots: void repaint_timeline(); void toggle_show_all(); + void toggle_links(); void deselect(); void split_at_playhead(); void ripple_delete(); diff --git a/project/footage.cpp b/project/footage.cpp index e1fd0fc5a..a08d052fc 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -159,8 +159,8 @@ FootageStream* Footage::get_stream_from_file_index(bool video, int index) { QString Footage::get_interlacing_name(int interlacing) { switch (interlacing) { case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)"); - case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Top Field First"); - case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Bottom Field First"); + case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Upper Field First"); + case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Lower Field First"); default: return QCoreApplication::translate("InterlacingName", "Invalid"); } } diff --git a/ui/effectui.cpp b/ui/effectui.cpp index d86658584..b3d03053d 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -127,9 +127,9 @@ EffectUI::EffectUI(Effect* e) : widgets_[i][j] = widget; - layout_->addWidget(widget, i, column, 1, field->GetColumnSpan()); + layout_->addWidget(widget, i, column, 1, 1); - column += field->GetColumnSpan(); + column++; } // Find maximum column to place keyframe controls @@ -237,7 +237,7 @@ void EffectUI::UpdateFromEffect() // Check if this UI object is attached to one effect or many if (additional_effects_.isEmpty()) { - field->UpdateWidgetValue(Widget(j, k), field->Now()); + field->UpdateWidgetValue(Widget(j, k), effect->Now()); } else { @@ -247,14 +247,14 @@ void EffectUI::UpdateFromEffect() EffectField* previous_field = i > 0 ? additional_effects_.at(i-1)->row(j)->Field(k) : field; EffectField* additional_field = additional_effects_.at(i)->row(j)->Field(k); - if (additional_field->GetValueAt(additional_field->Now()) != previous_field->GetValueAt(previous_field->Now())) { + if (additional_field->GetValueAt(additional_effects_.at(i)->Now()) != previous_field->GetValueAt(additional_effects_.at(i-1)->Now())) { same_value = false; break; } } if (same_value) { - field->UpdateWidgetValue(Widget(j, k), field->Now()); + field->UpdateWidgetValue(Widget(j, k), effect->Now()); } else { field->UpdateWidgetValue(Widget(j, k), qSNaN()); }