diff --git a/dialogs/clippropertiesdialog.cpp b/dialogs/clippropertiesdialog.cpp index 9d204db02..6f4be32fe 100644 --- a/dialogs/clippropertiesdialog.cpp +++ b/dialogs/clippropertiesdialog.cpp @@ -33,7 +33,7 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clip layout->addWidget(new QLabel(tr("Duration:")), row, 0); duration_field_ = new LabelSlider(); - duration_field_->set_display_type(LABELSLIDER_FRAMENUMBER); + duration_field_->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); duration_field_->set_minimum_value(1); layout->addWidget(duration_field_, row, 1); diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index 5b0035115..6f38cea38 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -48,7 +48,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0); percent = new LabelSlider(this); percent->decimal_places = 2; - percent->set_display_type(LABELSLIDER_PERCENT); + percent->set_display_type(LabelSlider::LABELSLIDER_PERCENT); percent->set_default_value(1); grid->addWidget(percent, 0, 1); @@ -59,7 +59,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0); duration = new LabelSlider(this); - duration->set_display_type(LABELSLIDER_FRAMENUMBER); + duration->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); duration->set_frame_rate(olive::ActiveSequence->frame_rate); grid->addWidget(duration, 2, 1); @@ -301,7 +301,10 @@ void SpeedDialog::frame_rate_update() { Clip* c = clips_.at(i); if (c->track() >= 0) { - long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? c->length() : ((c->length() * c->speed().value) / pc_val); + + long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? + c->length() : qRound((c->length() * c->speed().value) / pc_val); + if (len_val > -1 && new_clip_len != len_val) { len_val = -1; break; diff --git a/effects/internal/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp index 26671f253..56b98ca3a 100644 --- a/effects/internal/audionoiseeffect.cpp +++ b/effects/internal/audionoiseeffect.cpp @@ -1,4 +1,4 @@ -/* +/* * Olive. Olive is a free non-linear video editor for Windows, macOS, and Linux. * Copyright (C) 2018 {{ organization }} * @@ -21,14 +21,15 @@ #include AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount"); - amount_val->set_double_minimum_value(0); - amount_val->set_double_maximum_value(100); - amount_val->set_double_default_value(20); - - mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix"); - mix_val->set_bool_value(true); + EffectRow* amount_row = add_row(tr("Amount")); + amount_val = new DoubleField(amount_row, "amount"); + amount_val->SetMinimum(0); + amount_val->SetDefault(20); + amount_val->SetMaximum(100); + EffectRow* mix_row = add_row(tr("Mix")); + mix_val = new BoolField(mix_row, "mix"); + mix_val->SetValueAt(0, true); } void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) { @@ -40,12 +41,12 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, qint16 right_noise_sample = this->randomNumber(); // set noise volume - double vol = log_volume( amount_val->get_double_value(timecode, true)*0.01 ); + double vol = log_volume( amount_val->GetDoubleAt(timecode)*0.01 ); left_noise_sample *= vol; right_noise_sample *= vol; // mix with source audio - if (mix_val->get_bool_value(timecode, true)) { + if (mix_val->GetBoolAt(timecode)) { qint16 left_sample = static_cast (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); qint16 right_sample = static_cast (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); left_noise_sample = mix_audio_sample(left_noise_sample, left_sample); diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h index 2906499c9..f2668d354 100644 --- a/effects/internal/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -24,13 +24,13 @@ #include "project/effect.h" class AudioNoiseEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - AudioNoiseEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + AudioNoiseEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* amount_val; - EffectField* mix_val; + DoubleField* amount_val; + BoolField* mix_val; }; #endif // AUDIONOISEEFFECT_H diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index d00ecd571..315ed3f50 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -25,73 +25,73 @@ #include "debug.h" CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - enable_coords = true; - enable_shader = true; + SetFlags(Effect::CoordsFlag & Effect::ShaderFlag); - EffectRow* top_left = add_row(tr("Top Left")); - top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx"); - top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty"); + EffectRow* top_left = add_row(tr("Top Left")); + top_left_x = new DoubleField(top_left, "topleftx"); + top_left_y = new DoubleField(top_left, "toplefty"); - EffectRow* top_right = add_row(tr("Top Right")); - top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx"); - top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty"); + EffectRow* top_right = add_row(tr("Top Right")); + top_right_x = new DoubleField(top_right, "toprightx"); + top_right_y = new DoubleField(top_right, "toprighty"); - EffectRow* bottom_left = add_row(tr("Bottom Left")); - bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx"); - bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty"); + EffectRow* bottom_left = add_row(tr("Bottom Left")); + bottom_left_x = new DoubleField(bottom_left, "bottomleftx"); + bottom_left_y = new DoubleField(bottom_left, "bottomlefty"); - EffectRow* bottom_right = add_row(tr("Bottom Right")); - bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx"); - bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty"); + EffectRow* bottom_right = add_row(tr("Bottom Right")); + bottom_right_x = new DoubleField(bottom_right, "bottomrightx"); + bottom_right_y = new DoubleField(bottom_right, "bottomrighty"); - perspective = add_row(tr("Perspective"))->add_field(EFFECT_FIELD_BOOL, "perspective"); - perspective->set_bool_value(true); + EffectRow* perspective_row = add_row(tr("Perspective")); + perspective = new BoolField(perspective_row, "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 = add_gizmo(GIZMO_TYPE_DOT); + top_left_gizmo->x_field1 = top_left_x; + top_left_gizmo->y_field1 = top_left_y; - 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 = add_gizmo(GIZMO_TYPE_DOT); + top_right_gizmo->x_field1 = top_right_x; + top_right_gizmo->y_field1 = top_right_y; - 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 = add_gizmo(GIZMO_TYPE_DOT); + bottom_left_gizmo->x_field1 = bottom_left_x; + bottom_left_gizmo->y_field1 = bottom_left_y; - 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 = add_gizmo(GIZMO_TYPE_DOT); + bottom_right_gizmo->x_field1 = bottom_right_x; + bottom_right_gizmo->y_field1 = bottom_right_y; - vertPath = "cornerpin.vert"; - fragPath = "cornerpin.frag"; + vertPath = "cornerpin.vert"; + fragPath = "cornerpin.frag"; } void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) { - coords.vertexTopLeftX += top_left_x->get_double_value(timecode); - coords.vertexTopLeftY += top_left_y->get_double_value(timecode); + coords.vertexTopLeftX += top_left_x->GetDoubleAt(timecode); + coords.vertexTopLeftY += top_left_y->GetDoubleAt(timecode); - coords.vertexTopRightX += top_right_x->get_double_value(timecode); - coords.vertexTopRightY += top_right_y->get_double_value(timecode); + coords.vertexTopRightX += top_right_x->GetDoubleAt(timecode); + coords.vertexTopRightY += top_right_y->GetDoubleAt(timecode); - coords.vertexBottomLeftX += bottom_left_x->get_double_value(timecode); - coords.vertexBottomLeftY += bottom_left_y->get_double_value(timecode); + coords.vertexBottomLeftX += bottom_left_x->GetDoubleAt(timecode); + coords.vertexBottomLeftY += bottom_left_y->GetDoubleAt(timecode); - coords.vertexBottomRightX += bottom_right_x->get_double_value(timecode); - coords.vertexBottomRightY += bottom_right_y->get_double_value(timecode); + coords.vertexBottomRightX += bottom_right_x->GetDoubleAt(timecode); + coords.vertexBottomRightY += bottom_right_y->GetDoubleAt(timecode); } void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) { - glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY)); - glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY)); - glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY)); - glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY)); - glslProgram->setUniformValue("perspective", perspective->get_bool_value(timecode)); + glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY)); + glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY)); + glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY)); + glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY)); + glslProgram->setUniformValue("perspective", perspective->GetBoolAt(timecode)); } void CornerPinEffect::gizmo_draw(double, GLTextureCoords &coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); } diff --git a/effects/internal/cornerpineffect.h b/effects/internal/cornerpineffect.h index b1591246d..5b2460ef8 100644 --- a/effects/internal/cornerpineffect.h +++ b/effects/internal/cornerpineffect.h @@ -24,27 +24,27 @@ #include "project/effect.h" class CornerPinEffect : public Effect { - Q_OBJECT + Q_OBJECT public: CornerPinEffect(Clip* c, const EffectMeta* em); - void process_coords(double timecode, GLTextureCoords& coords, int data); - void process_shader(double timecode, GLTextureCoords& coords, int iterations); - void gizmo_draw(double timecode, GLTextureCoords& coords); + void process_coords(double timecode, GLTextureCoords& coords, int data); + void process_shader(double timecode, GLTextureCoords& coords, int iterations); + void gizmo_draw(double timecode, GLTextureCoords& coords); private: - EffectField* top_left_x; - EffectField* top_left_y; - EffectField* top_right_x; - EffectField* top_right_y; - EffectField* bottom_left_x; - EffectField* bottom_left_y; - EffectField* bottom_right_x; - EffectField* bottom_right_y; - EffectField* perspective; + 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; - EffectGizmo* top_left_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_right_gizmo; + EffectGizmo* top_left_gizmo; + EffectGizmo* top_right_gizmo; + EffectGizmo* bottom_left_gizmo; + EffectGizmo* bottom_right_gizmo; }; #endif // CORNERPINEFFECT_H diff --git a/effects/internal/crossdissolvetransition.cpp b/effects/internal/crossdissolvetransition.cpp index ba495346d..a90fbbeff 100644 --- a/effects/internal/crossdissolvetransition.cpp +++ b/effects/internal/crossdissolvetransition.cpp @@ -23,14 +23,12 @@ #include CrossDissolveTransition::CrossDissolveTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) { - enable_coords = true; - -// add_row("Smooth")->add_field(EFFECT_FIELD_BOOL, "smooth"); + SetFlags(Effect::CoordsFlag); } void CrossDissolveTransition::process_coords(double progress, GLTextureCoords& coords, int data) { - if (!(data == kTransitionClosing && secondary_clip != nullptr)) { - if (data == kTransitionClosing) progress = 1.0 - progress; - coords.opacity *= progress; - } + if (!(data == kTransitionClosing && secondary_clip != nullptr)) { + if (data == kTransitionClosing) progress = 1.0 - progress; + coords.opacity *= progress; + } } diff --git a/effects/internal/cubetransition.cpp b/effects/internal/cubetransition.cpp deleted file mode 100644 index 829ad820d..000000000 --- a/effects/internal/cubetransition.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "cubetransition.h" - -#include "debug.h" - -CubeTransition::CubeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) { - enable_coords = true; -} - -void CubeTransition::process_coords(double, GLTextureCoords& coords, int) { - - coords.vertexTopLeftZ = 1; - coords.vertexBottomLeftZ = 1; -} diff --git a/effects/internal/fillleftrighteffect.cpp b/effects/internal/fillleftrighteffect.cpp index e6e687839..d23efa04f 100644 --- a/effects/internal/fillleftrighteffect.cpp +++ b/effects/internal/fillleftrighteffect.cpp @@ -24,21 +24,21 @@ #define FILL_TYPE_RIGHT 1 FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* type_row = add_row(tr("Type")); - fill_type = type_row->add_field(EFFECT_FIELD_COMBO, "type"); - fill_type->add_combo_item(tr("Fill Left with Right"), FILL_TYPE_LEFT); - fill_type->add_combo_item(tr("Fill Right with Left"), FILL_TYPE_RIGHT); + EffectRow* type_row = add_row(tr("Type")); + fill_type = new ComboField(type_row, "type"); + fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT); + fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT); } void FillLeftRightEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end-timecode_start)/nb_bytes; - for (int i=0;iget_combo_data(timecode_start+(interval*i)) == FILL_TYPE_LEFT) { - samples[i+1] = samples[i+3]; - samples[i] = samples[i+2]; - } else { - samples[i+3] = samples[i+1]; - samples[i+2] = samples[i]; - } - } + double interval = (timecode_end-timecode_start)/nb_bytes; + for (int i=0;iGetValueAt(timecode_start+(interval*i)) == FILL_TYPE_LEFT) { + samples[i+1] = samples[i+3]; + samples[i] = samples[i+2]; + } else { + samples[i+3] = samples[i+1]; + samples[i+2] = samples[i]; + } + } } diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h index 198f44dcb..6a47a31ac 100644 --- a/effects/internal/fillleftrighteffect.h +++ b/effects/internal/fillleftrighteffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class FillLeftRightEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - FillLeftRightEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + FillLeftRightEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); private: - EffectField* fill_type; + ComboField* fill_type; }; #endif // FILLLEFTRIGHTEFFECT_H diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index 223cd0cce..ea0b86f75 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -31,184 +31,184 @@ typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int heig typedef int (*f0rInitFunc) (); typedef void (*f0rDeinitFunc) (); typedef void (*f0rUpdateFunc) (f0r_instance_t instance, - double time, const uint32_t* inframe, uint32_t* outframe); + double time, const uint32_t* inframe, uint32_t* outframe); typedef void (*f0rDestructFunc)(f0r_instance_t instance); typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); typedef void (*f0rSetParamValue) (f0r_instance_t instance, - f0r_param_t param, int param_index); + f0r_param_t param, int param_index); Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : - Effect(c, em), - open(false) + Effect(c, em), + open(false) { - enable_image = true; + SetFlags(ImageFlag); - // Windows DLL loading routine - QString dll_fn = QDir(em->path).filePath(em->filename); + // Windows DLL loading routine + QString dll_fn = QDir(em->path).filePath(em->filename); - handle = LibLoad(dll_fn); - if(handle == nullptr) { - QString dll_error; + handle = LibLoad(dll_fn); + if(handle == nullptr) { + QString dll_error; #ifdef _WIN32 - DWORD dll_err = GetLastError(); - dll_error = QString::number(dll_err); + DWORD dll_err = GetLastError(); + dll_error = QString::number(dll_err); #elif __linux__ - dll_error = dlerror(); + dll_error = dlerror(); #endif - qCritical() << "Failed to load Frei0r plugin" << dll_fn << "-" << dll_error; + qCritical() << "Failed to load Frei0r plugin" << dll_fn << "-" << dll_error; - QString msg_err = tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error); + QString msg_err = tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error); #ifdef _WIN32 - if (dll_err == 193) { + if (dll_err == 193) { #ifdef _WIN64 - msg_err += "\n\n" + tr("NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); + msg_err += "\n\n" + tr("NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); #elif _WIN32 - msg_err += "\n\n" + tr("NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); + msg_err += "\n\n" + tr("NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); #endif - } + } #endif - QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), msg_err); + QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), msg_err); - return; - } + return; + } - f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); - init(); + f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); + init(); - construct_module(); + construct_module(); - f0r_plugin_info_t info; - f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); - info_func(&info); + f0r_plugin_info_t info; + f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); + info_func(&info); - param_count = info.num_params; + param_count = info.num_params; - get_param_info = reinterpret_cast(LibAddress(handle, "f0r_get_param_info")); - for (int i=0;i(LibAddress(handle, "f0r_get_param_info")); + for (int i=0;i= 0 && param_info.type <= F0R_PARAM_STRING) { - EffectRow* row = add_row(param_info.name); - switch (param_info.type) { - case F0R_PARAM_BOOL: - row->add_field(EFFECT_FIELD_BOOL, QString::number(i)); - break; - case F0R_PARAM_DOUBLE: - { - EffectField* f = row->add_field(EFFECT_FIELD_DOUBLE, QString::number(i)); - f->set_double_minimum_value(0); - f->set_double_maximum_value(100); - } - break; - case F0R_PARAM_COLOR: - row->add_field(EFFECT_FIELD_COLOR, QString::number(i)); - break; - case F0R_PARAM_POSITION: - { - EffectField* fx = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1X").arg(QString::number(i))); - fx->set_double_minimum_value(0); - fx->set_double_maximum_value(100); - EffectField* fy = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1Y").arg(QString::number(i))); - fy->set_double_minimum_value(0); - fy->set_double_maximum_value(100); - } - break; - case F0R_PARAM_STRING: - row->add_field(EFFECT_FIELD_STRING, QString::number(i)); - break; - } - } - } + if (param_info.type >= 0 && param_info.type <= F0R_PARAM_STRING) { + EffectRow* row = add_row(param_info.name); + switch (param_info.type) { + case F0R_PARAM_BOOL: + new BoolField(row, QString::number(i)); + break; + case F0R_PARAM_DOUBLE: + { + DoubleField* f = new DoubleField(row, QString::number(i)); + f->SetMinimum(0); + f->SetMaximum(100); + } + break; + case F0R_PARAM_COLOR: + new ColorField(row, QString::number(i)); + break; + case F0R_PARAM_POSITION: + { + DoubleField* fx = new DoubleField(row, QString("%1X").arg(QString::number(i))); + fx->SetMinimum(0); + fx->SetMaximum(100); + DoubleField* fy = new DoubleField(row, QString("%1Y").arg(QString::number(i))); + fy->SetMinimum(0); + fy->SetMaximum(100); + } + break; + case F0R_PARAM_STRING: + new StringField(row, QString::number(i)); + break; + } + } + } } Frei0rEffect::~Frei0rEffect() { - if (handle != nullptr) { - f0rDeinitFunc deinit = reinterpret_cast(LibAddress(handle, "f0r_deinit")); - deinit(); + if (handle != nullptr) { + f0rDeinitFunc deinit = reinterpret_cast(LibAddress(handle, "f0r_deinit")); + deinit(); - LibClose(handle); - } + LibClose(handle); + } } void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) { - f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); + f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); - for (int i=0;i(LibAddress(handle, "f0r_set_param_value")); - switch (param_info.type) { - case F0R_PARAM_BOOL: - { - double b = param_row->field(0)->get_bool_value(timecode); - set_param(instance, &b, i); - } - break; - case F0R_PARAM_DOUBLE: - { - double d = param_row->field(0)->get_double_value(timecode)*0.01; - set_param(instance, &d, i); - } - break; - case F0R_PARAM_COLOR: - { - QColor qcolor = param_row->field(0)->get_color_value(timecode);; + f0rSetParamValue set_param = reinterpret_cast(LibAddress(handle, "f0r_set_param_value")); + switch (param_info.type) { + case F0R_PARAM_BOOL: + { + double b = param_row->field(0)->GetValueAt(timecode).toBool(); + set_param(instance, &b, i); + } + break; + case F0R_PARAM_DOUBLE: + { + double d = param_row->field(0)->GetValueAt(timecode).toDouble()*0.01; + set_param(instance, &d, i); + } + break; + case F0R_PARAM_COLOR: + { + QColor qcolor = param_row->field(0)->GetValueAt(timecode).value(); - f0r_param_color fcolor; - fcolor.r = float(qcolor.redF()); - fcolor.g = float(qcolor.greenF()); - fcolor.b = float(qcolor.blueF()); + f0r_param_color fcolor; + fcolor.r = float(qcolor.redF()); + fcolor.g = float(qcolor.greenF()); + fcolor.b = float(qcolor.blueF()); - set_param(instance, &fcolor, i); - } - break; - case F0R_PARAM_POSITION: - { - f0r_param_position pos; - pos.x = param_row->field(0)->get_double_value(timecode); - pos.y = param_row->field(1)->get_double_value(timecode); - set_param(instance, &pos, i); - } - break; - case F0R_PARAM_STRING: - { - QByteArray bytes = param_row->field(0)->get_string_value(timecode).toUtf8(); - char* byte_data = bytes.data(); - set_param(instance, &byte_data, i); - } - break; - } - } + set_param(instance, &fcolor, i); + } + break; + case F0R_PARAM_POSITION: + { + f0r_param_position pos; + pos.x = param_row->field(0)->GetValueAt(timecode).toDouble(); + pos.y = param_row->field(1)->GetValueAt(timecode).toDouble(); + set_param(instance, &pos, i); + } + break; + case F0R_PARAM_STRING: + { + QByteArray bytes = param_row->field(0)->GetValueAt(timecode).toString().toUtf8(); + char* byte_data = bytes.data(); + set_param(instance, &byte_data, i); + } + break; + } + } - update_func(instance, timecode, reinterpret_cast(input), reinterpret_cast(output)); + update_func(instance, timecode, reinterpret_cast(input), reinterpret_cast(output)); } void Frei0rEffect::refresh() { - destruct_module(); - construct_module(); + destruct_module(); + construct_module(); } void Frei0rEffect::destruct_module() { - if (open) { - f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); - destruct(instance); + if (open) { + f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); + destruct(instance); - open = false; - } + open = false; + } } void Frei0rEffect::construct_module() { - f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); + f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); instance = construct(parent_clip->media_width(), parent_clip->media_height()); - open = true; + open = true; } #endif diff --git a/effects/internal/paneffect.cpp b/effects/internal/paneffect.cpp index babb0b01b..7ebb3af8e 100644 --- a/effects/internal/paneffect.cpp +++ b/effects/internal/paneffect.cpp @@ -29,35 +29,33 @@ #include "ui/collapsiblewidget.h" PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* pan_row = add_row(tr("Pan")); - pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan"); - pan_val->set_double_minimum_value(-100); - pan_val->set_double_maximum_value(100); - - // set defaults - pan_val->set_double_default_value(0); + EffectRow* pan_row = add_row(tr("Pan")); + pan_val = new DoubleField(pan_row, "pan"); + pan_val->SetMinimum(-100); + pan_val->SetDefault(0); + pan_val->SetMaximum(100); } void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end - timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode_start+(interval*i), true); - double pval = log_volume(qAbs(pan_field_val)*0.01); + double interval = (timecode_end - timecode_start)/nb_bytes; + for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); + double pval = log_volume(qAbs(pan_field_val)*0.01); - qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - if (pan_field_val < 0) { - // affect right channel - right_sample *= (1.0-pval); - } else { - // affect left channel - left_sample *= (1.0-pval); - } + if (pan_field_val < 0) { + // affect right channel + right_sample *= (1.0-pval); + } else { + // affect left channel + left_sample *= (1.0-pval); + } - samples[i+3] = quint8(right_sample >> 8); - samples[i+2] = quint8(right_sample); - samples[i+1] = quint8(left_sample >> 8); - samples[i] = quint8(left_sample); - } + samples[i+3] = quint8(right_sample >> 8); + samples[i+2] = quint8(right_sample); + samples[i+1] = quint8(left_sample >> 8); + samples[i] = quint8(left_sample); + } } diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h index 7640c48be..aab759b54 100644 --- a/effects/internal/paneffect.h +++ b/effects/internal/paneffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class PanEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - PanEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + PanEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* pan_val; + DoubleField* pan_val; }; #endif // PANEFFECT_H diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index a8d5f53f7..e27cb912a 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -34,62 +34,60 @@ #include "debug.h" ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - enable_coords = true; + SetFlags(Effect::CoordsFlag); - EffectRow* intensity_row = add_row(tr("Intensity")); - intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity"); - intensity_val->set_double_minimum_value(0); + EffectRow* intensity_row = add_row(tr("Intensity")); + intensity_val = new DoubleField(intensity_row, "intensity"); + intensity_val->SetMinimum(0); + intensity_val->SetDefault(25); - EffectRow* rotation_row = add_row(tr("Rotation")); - rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); - rotation_val->set_double_minimum_value(0); + EffectRow* rotation_row = add_row(tr("Rotation")); + rotation_val = new DoubleField(rotation_row, "rotation"); + rotation_val->SetMinimum(0); + rotation_val->SetDefault(10); - EffectRow* frequency_row = add_row(tr("Frequency")); - frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency"); - frequency_val->set_double_minimum_value(0); + EffectRow* frequency_row = add_row(tr("Frequency")); + frequency_val = new DoubleField(frequency_row, "frequency"); + frequency_val->SetMinimum(0); + frequency_val->SetDefault(5); - // set defaults - intensity_val->set_double_default_value(25); - rotation_val->set_double_default_value(10); - frequency_val->set_double_default_value(5); - - const auto limit = std::numeric_limits::max(); - for (int i=0;i(this->randomNumber()) / limit; - } + const auto limit = std::numeric_limits::max(); + for (int i=0;i(this->randomNumber()) / limit; + } } void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - int lim = RANDOM_VAL_SIZE/6; + int lim = RANDOM_VAL_SIZE/6; - double multiplier = intensity_val->get_double_value(timecode)/lim; - double rotmult = rotation_val->get_double_value(timecode)/lim/10; - double x = timecode * frequency_val->get_double_value(timecode); + double multiplier = intensity_val->GetDoubleAt(timecode)/lim; + double rotmult = rotation_val->GetDoubleAt(timecode)/lim/10; + double x = timecode * frequency_val->GetDoubleAt(timecode); - double xoff = 0; - double yoff = 0; - double rotoff = 0; + double xoff = 0; + double yoff = 0; + double rotoff = 0; - for (int i=0;iAddItem(tr("Solid Color"), SOLID_TYPE_COLOR); + solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS); + solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); - solid_type = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type"); - solid_type->add_combo_item(tr("Solid Color"), SOLID_TYPE_COLOR); - solid_type->add_combo_item(tr("SMPTE Bars"), SOLID_TYPE_BARS); - solid_type->add_combo_item(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); + EffectRow* opacity_row = add_row(tr("Opacity")); + opacity_field = new DoubleField(opacity_row, "opacity"); + opacity_field->SetMinimum(0); + opacity_field->SetDefault(0); + opacity_field->SetMaximum(100); - opacity_field = add_row(tr("Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "opacity"); - opacity_field->set_double_minimum_value(0); - opacity_field->set_double_maximum_value(100); - opacity_field->set_double_default_value(100); + EffectRow* solid_color_row = add_row(tr("Color")); + solid_color_field = new ColorField(solid_color_row, "color"); + solid_color_field->SetValueAt(0, QColor(Qt::red)); - solid_color_field = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color"); - solid_color_field->set_color_value(Qt::red); + EffectRow* checkerboard_size = add_row(tr("Checkerboard Size")); + checkerboard_size_field = new DoubleField(checkerboard_size, "checker_size"); + checkerboard_size_field->SetMinimum(1); + checkerboard_size_field->SetDefault(10); - checkerboard_size_field = add_row(tr("Checkerboard Size"))->add_field(EFFECT_FIELD_DOUBLE, "checker_size"); - checkerboard_size_field->set_double_minimum_value(1); - checkerboard_size_field->set_double_default_value(10); + connect(solid_type, SIGNAL(IndexChanged(int)), this, SLOT(ui_update(int))); - // hacky but eh - QComboBox* solid_type_combo = static_cast(solid_type->get_ui_element()); - connect(solid_type_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(ui_update(int))); - ui_update(solid_type_combo->currentIndex()); + // Set default UI + solid_type->SetValueAt(0, SOLID_TYPE_COLOR); - /*vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/solideffect.frag";*/ + // TODO necessary? Isn't this called from the connect() above? + ui_update(SOLID_TYPE_COLOR); + + /*vertPath = ":/shaders/common.vert"; + fragPath = ":/shaders/solideffect.frag";*/ } void SolidEffect::redraw(double timecode) { - int w = img.width(); - int h = img.height(); - int alpha = qRound(opacity_field->get_double_value(timecode)*2.55); - switch (solid_type->get_combo_data(timecode).toInt()) { - case SOLID_TYPE_COLOR: - { - QColor solidColor = solid_color_field->get_color_value(timecode); - solidColor.setAlpha(alpha); - img.fill(solidColor); - } - break; - case SOLID_TYPE_BARS: - { - // draw smpte bars - QPainter p(&img); - img.fill(Qt::transparent); - int bar_width = qCeil((double) w / 7.0); - int first_bar_height = qCeil((double) h / 3.0 * 2.0); - int second_bar_height = qCeil((double) h / 12.5); - int third_bar_y = first_bar_height + second_bar_height; - int third_bar_height = h - third_bar_y; - int third_bar_width = 0; - int bar_x, strip_width; - QColor first_color, second_color, third_color; - for (int i=0;iGetDoubleAt(timecode)*2.55); + switch (solid_type->GetValueAt(timecode).toInt()) { + case SOLID_TYPE_COLOR: + { + QColor solidColor = solid_color_field->GetColorAt(timecode); + solidColor.setAlpha(alpha); + img.fill(solidColor); + } + break; + case SOLID_TYPE_BARS: + { + // draw smpte bars + QPainter p(&img); + img.fill(Qt::transparent); + int bar_width = qCeil(double(w) / 7.0); + int first_bar_height = qCeil(double(h) / 3.0 * 2.0); + int second_bar_height = qCeil(double(h) / 12.5); + int third_bar_y = first_bar_height + second_bar_height; + int third_bar_height = h - third_bar_y; + int third_bar_width = 0; + int bar_x, strip_width; + QColor first_color, second_color, third_color; + for (int i=0;iget_double_value(timecode)); - int checker_x, checker_y; - int checkerboard_size_w = qCeil(double(w)/checker_width); - int checkerboard_size_h = qCeil(double(h)/checker_width); + int checker_width = qCeil(checkerboard_size_field->GetDoubleAt(timecode)); + int checker_x, checker_y; + int checkerboard_size_w = qCeil(double(w)/checker_width); + int checkerboard_size_h = qCeil(double(h)/checker_width); - QColor checker_odd(QColor(0, 0, 0, alpha)); - QColor checker_even(solid_color_field->get_color_value(timecode)); - checker_even.setAlpha(alpha); - QVector checker_color{checker_odd, checker_even}; + QColor checker_odd(QColor(0, 0, 0, alpha)); + QColor checker_even(solid_color_field->GetColorAt(timecode)); + checker_even.setAlpha(alpha); + QVector checker_color{checker_odd, checker_even}; - for(int i = 0; i < checkerboard_size_w; i++){ - checker_x = checker_width*i; - for(int j = 0; j < checkerboard_size_h; j++){ - checker_y = checker_width*j; - p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]); - } - } - } - break; - } + for(int i = 0; i < checkerboard_size_w; i++){ + checker_x = checker_width*i; + for(int j = 0; j < checkerboard_size_h; j++){ + checker_y = checker_width*j; + p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]); + } + } + } + break; + } +} + +void SolidEffect::SetType(SolidEffect::SolidType type) +{ + solid_type->SetValueAt(0, type); } void SolidEffect::ui_update(int i) { - solid_color_field->set_enabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); - checkerboard_size_field->set_enabled(i == SOLID_TYPE_CHECKERBOARD); + solid_color_field->SetEnabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); + checkerboard_size_field->SetEnabled(i == SOLID_TYPE_CHECKERBOARD); } diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h index 9175e02e6..0b5b22846 100644 --- a/effects/internal/solideffect.h +++ b/effects/internal/solideffect.h @@ -26,17 +26,25 @@ #include class SolidEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - SolidEffect(Clip* c, const EffectMeta *em); - void redraw(double timecode); + enum SolidType { + SOLID_TYPE_COLOR, + SOLID_TYPE_BARS, + SOLID_TYPE_CHECKERBOARD + }; + + SolidEffect(Clip* c, const EffectMeta *em); + virtual void redraw(double timecode); + + void SetType(SolidType type); private slots: - void ui_update(int); + void ui_update(int); private: - EffectField* solid_type; - EffectField* solid_color_field; - EffectField* opacity_field; - EffectField* checkerboard_size_field; + ComboField* solid_type; + ColorField* solid_color_field; + DoubleField* opacity_field; + DoubleField* checkerboard_size_field; }; #endif // SOLIDEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index bb3b5de41..f3fecf396 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -40,314 +40,326 @@ #include "ui/comboboxex.h" #include "ui/colorbutton.h" #include "ui/fontcombobox.h" -#include "dialogs/texteditdialog.h" #include "io/config.h" -#include "mainwindow.h" TextEffect::TextEffect(Clip* c, const EffectMeta* em) : - Effect(c, em) + Effect(c, em) { - enable_superimpose = true; + SetFlags(Effect::SuperimposeFlag); - text_val = add_row(tr("Text"))->add_field(EFFECT_FIELD_STRING, "text", 2); - QTextEdit* text_widget = static_cast(text_val->ui_element); - text_widget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(text_widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); + EffectRow* text_field = add_row(tr("Text")); + text_val = new StringField(text_field, "text"); + text_val->SetColumnSpan(2); - set_font_combobox = add_row(tr("Font"))->add_field(EFFECT_FIELD_FONT, "font", 2); + EffectRow* font_row = add_row(tr("Font")); + set_font_combobox = new FontField(font_row, "font"); + set_font_combobox->SetColumnSpan(2); - size_val = add_row(tr("Size"))->add_field(EFFECT_FIELD_DOUBLE, "size", 2); - size_val->set_double_minimum_value(0); + EffectRow* size_row = add_row(tr("Size")); + size_val = new DoubleField(size_row, "size"); + size_val->SetMinimum(0); + size_val->SetColumnSpan(2); - set_color_button = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2); + EffectRow* color_row = add_row(tr("Color")); + set_color_button = new ColorField(color_row, "color"); + set_color_button->SetColumnSpan(2); - EffectRow* alignment_row = add_row(tr("Alignment")); - halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign"); - halign_field->add_combo_item(tr("Left"), Qt::AlignLeft); - halign_field->add_combo_item(tr("Center"), Qt::AlignHCenter); - halign_field->add_combo_item(tr("Right"), Qt::AlignRight); - halign_field->add_combo_item(tr("Justify"), Qt::AlignJustify); + EffectRow* alignment_row = add_row(tr("Alignment")); + halign_field = new ComboField(alignment_row, "halign"); + 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 = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign"); - valign_field->add_combo_item(tr("Top"), Qt::AlignTop); - valign_field->add_combo_item(tr("Center"), Qt::AlignVCenter); - valign_field->add_combo_item(tr("Bottom"), Qt::AlignBottom); + valign_field = new ComboField(alignment_row, "valign"); + valign_field->AddItem(tr("Top"), Qt::AlignTop); + valign_field->AddItem(tr("Center"), Qt::AlignVCenter); + valign_field->AddItem(tr("Bottom"), Qt::AlignBottom); - word_wrap_field = add_row(tr("Word Wrap"))->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2); + EffectRow* word_wrap_row = add_row(tr("Word Wrap")); + word_wrap_field = new BoolField(word_wrap_row, "wordwrap"); + word_wrap_field->SetColumnSpan(2); - outline_bool = add_row(tr("Outline"))->add_field(EFFECT_FIELD_BOOL, "outline", 2); - outline_color = add_row(tr("Outline Color"))->add_field(EFFECT_FIELD_COLOR, "outlinecolor", 2); - outline_width = add_row(tr("Outline Width"))->add_field(EFFECT_FIELD_DOUBLE, "outlinewidth", 2); - outline_width->set_double_minimum_value(0); + EffectRow* outline_row = add_row(tr("Outline")); + outline_bool = new BoolField(outline_row, "outline"); + outline_bool->SetColumnSpan(2); - shadow_bool = add_row(tr("Shadow"))->add_field(EFFECT_FIELD_BOOL, "shadow", 2); - shadow_color = add_row(tr("Shadow Color"))->add_field(EFFECT_FIELD_COLOR, "shadowcolor", 2); - shadow_angle = add_row(tr("Shadow Angle"))->add_field(EFFECT_FIELD_DOUBLE, "shadowangle", 2); - shadow_distance = add_row(tr("Shadow Distance"))->add_field(EFFECT_FIELD_DOUBLE, "shadowdistance", 2); - shadow_distance->set_double_minimum_value(0); - shadow_softness = add_row(tr("Shadow Softness"))->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2); - shadow_softness->set_double_minimum_value(0); - shadow_opacity = add_row(tr("Shadow Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2); - shadow_opacity->set_double_minimum_value(0); - shadow_opacity->set_double_maximum_value(100); + EffectRow* outline_color_row = add_row(tr("Outline Color")); + outline_color = new ColorField(outline_color_row, "outlinecolor"); + outline_color->SetColumnSpan(2); - size_val->set_double_default_value(48); - text_val->set_string_value(tr("Sample Text")); - halign_field->set_combo_index(1); - valign_field->set_combo_index(1); - word_wrap_field->set_bool_value(true); - outline_color->set_color_value(Qt::black); - shadow_color->set_color_value(Qt::black); - shadow_angle->set_double_default_value(45); - shadow_opacity->set_double_default_value(100); - shadow_softness->set_double_default_value(5); - shadow_distance->set_double_default_value(5); - shadow_opacity->set_double_default_value(80); - outline_width->set_double_default_value(20); + EffectRow* outline_width_row = add_row(tr("Outline Width")); + outline_width = new DoubleField(outline_width_row, "outlinewidth"); + outline_width->SetColumnSpan(2); + outline_width->SetMinimum(0); - outline_enable(false); - shadow_enable(false); + EffectRow* shadow_row = add_row(tr("Shadow")); + shadow_bool = new BoolField(shadow_row, "shadow"); + shadow_bool->SetColumnSpan(2); - connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool))); - connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool))); + EffectRow* shadow_color_row = add_row(tr("Shadow Color")); + shadow_color = new ColorField(shadow_color_row, "shadowcolor"); + shadow_color->SetColumnSpan(2); - vertPath = "common.vert"; - fragPath = "dropshadow.frag"; + EffectRow* shadow_angle_row = add_row(tr("Shadow Angle")); + shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); + shadow_angle->SetColumnSpan(2); + + EffectRow* shadow_distance_row = add_row(tr("Shadow Distance")); + shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); + shadow_distance->SetColumnSpan(2); + shadow_distance->SetMinimum(0); + + EffectRow* shadow_softness_row = add_row(tr("Shadow Softness")); + shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); + shadow_softness->SetColumnSpan(2); + shadow_softness->SetMinimum(0); + + EffectRow* shadow_opacity_row = add_row(tr("Shadow Opacity")); + shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); + shadow_opacity->SetColumnSpan(2); + shadow_opacity->SetMinimum(0); + shadow_opacity->SetMaximum(100); + + size_val->SetDefault(48); + text_val->SetValueAt(0, tr("Sample Text")); + halign_field->SetValueAt(0, Qt::AlignHCenter); + valign_field->SetValueAt(0, Qt::AlignVCenter); + word_wrap_field->SetValueAt(0, true); + outline_color->SetValueAt(0, QColor(Qt::black)); + shadow_color->SetValueAt(0, QColor(Qt::black)); + shadow_angle->SetDefault(45); + shadow_opacity->SetDefault(100); + shadow_softness->SetDefault(5); + shadow_distance->SetDefault(5); + shadow_opacity->SetDefault(80); + outline_width->SetDefault(20); + + outline_enable(false); + shadow_enable(false); + + connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool))); + connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool))); + + vertPath = "common.vert"; + fragPath = "dropshadow.frag"; } void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; + int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); + int r1 = rect.top(); + int r2 = rect.bottom(); + int c1 = rect.left(); + int c2 = rect.right(); - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; + int bpl = result.bytesPerLine(); + int rgba[4]; + unsigned char* p; - int i1 = 0; - int i2 = 3; + int i1 = 0; + int i2 = 3; - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); + if (alphaOnly) + i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r1) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += bpl; + for (int j = r1; j < r2; j++, p += bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c1 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += 4; + for (int j = c1; j < c2; j++, p += 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r2) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= bpl; + for (int j = r1; j < r2; j++, p -= bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c2 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= 4; + for (int j = c1; j < c2; j++, p -= 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } } void TextEffect::redraw(double timecode) { - QColor bkg = set_color_button->get_color_value(timecode); - bkg.setAlpha(0); - img.fill(bkg); + QColor bkg = set_color_button->GetColorAt(timecode); + bkg.setAlpha(0); + img.fill(bkg); - QPainter p(&img); - p.setRenderHint(QPainter::Antialiasing); - int width = img.width(); - int height = img.height(); + QPainter p(&img); + p.setRenderHint(QPainter::Antialiasing); + int width = img.width(); + int height = img.height(); - // set font - font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); - font.setFamily(set_font_combobox->get_font_name(timecode)); - font.setPointSize(size_val->get_double_value(timecode)); - p.setFont(font); - QFontMetrics fm(font); + // set font + font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); + font.setFamily(set_font_combobox->GetFontAt(timecode)); + font.setPointSize(qRound(size_val->GetDoubleAt(timecode))); + p.setFont(font); + QFontMetrics fm(font); - QStringList lines = text_val->get_string_value(timecode).split('\n'); + QStringList lines = text_val->GetStringAt(timecode).split('\n'); - // word wrap function - if (word_wrap_field->get_bool_value(timecode)) { - for (int i=0;i width) { - int last_space_index = 0; - for (int j=0;j width) { - break; - } else { - last_space_index = j; - } - } - } - if (last_space_index > 0) { - lines.insert(i+1, s.mid(last_space_index + 1)); - lines[i] = s.left(last_space_index); - } - } - } - } + // word wrap function + if (word_wrap_field->GetBoolAt(timecode)) { + for (int i=0;i width) { + int last_space_index = 0; + for (int j=0;j width) { + break; + } else { + last_space_index = j; + } + } + } + if (last_space_index > 0) { + lines.insert(i+1, s.mid(last_space_index + 1)); + lines[i] = s.left(last_space_index); + } + } + } + } - QPainterPath path; + QPainterPath path; - int text_height = fm.height()*lines.size(); + int text_height = fm.height()*lines.size(); - for (int i=0;iget_combo_data(timecode).toInt()) { - case Qt::AlignLeft: text_x = 0; break; - case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; - case Qt::AlignJustify: - // add spaces until the string is too big - text_x = 0; - while (fm.width(lines.at(i)) < width) { - bool space = false; - QString spaced(lines.at(i)); - for (int i=0;iGetValueAt(timecode).toInt()) { + case Qt::AlignLeft: text_x = 0; break; + case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; + case Qt::AlignJustify: + // add spaces until the string is too big + text_x = 0; + while (fm.width(lines.at(i)) < width) { + bool space = false; + QString spaced(lines.at(i)); + for (int i=0;i width || !space) { - break; - } else { - lines[i] = spaced; - } - } - break; - case Qt::AlignHCenter: - default: - text_x = (width/2) - (fm.width(lines.at(i))/2); - break; - } + // scan to next non-space + while (i < spaced.length() && spaced.at(i) == ' ') i++; + } + } + if (fm.width(spaced) > width || !space) { + break; + } else { + lines[i] = spaced; + } + } + break; + case Qt::AlignHCenter: + default: + text_x = (width/2) - (fm.width(lines.at(i))/2); + break; + } - switch (valign_field->get_combo_data(timecode).toInt()) { - case Qt::AlignTop: - text_y = (fm.height()*i)+fm.ascent(); - break; - case Qt::AlignBottom: - text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); - break; - case Qt::AlignVCenter: - default: - text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); - break; - } + switch (valign_field->GetValueAt(timecode).toInt()) { + case Qt::AlignTop: + text_y = (fm.height()*i)+fm.ascent(); + break; + case Qt::AlignBottom: + text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); + break; + case Qt::AlignVCenter: + default: + text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); + break; + } - path.addText(text_x, text_y, font, lines.at(i)); - } + path.addText(text_x, text_y, font, lines.at(i)); + } - // draw software shadow - if (shadow_bool->get_bool_value(timecode)) { - p.setPen(Qt::NoPen); + // draw software shadow + if (shadow_bool->GetBoolAt(timecode)) { + p.setPen(Qt::NoPen); // calculate offset using distance and angle - double angle = shadow_angle->get_double_value(timecode) * M_PI / 180.0; - double distance = qFloor(shadow_distance->get_double_value(timecode)); + double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0; + double distance = qFloor(shadow_distance->GetDoubleAt(timecode)); int shadow_x_offset = qRound(qCos(angle) * distance); int shadow_y_offset = qRound(qSin(angle) * distance); - QPainterPath shadow_path(path); + QPainterPath shadow_path(path); shadow_path.translate(shadow_x_offset, shadow_y_offset); - QColor col = shadow_color->get_color_value(timecode); - col.setAlpha(0); - img.fill(col); + QColor col = shadow_color->GetColorAt(timecode); + col.setAlpha(0); + img.fill(col); - col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01); - p.setBrush(col); - p.drawPath(shadow_path); + col.setAlphaF(shadow_opacity->GetDoubleAt(timecode)*0.01); + p.setBrush(col); + p.drawPath(shadow_path); - int blurSoftness = qFloor(shadow_softness->get_double_value(timecode)); + int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, true); - } + } - // draw outline - int outline_width_val = outline_width->get_double_value(timecode); - if (outline_bool->get_bool_value(timecode) && outline_width_val > 0) { - QPen outline(outline_color->get_color_value(timecode)); - outline.setWidth(outline_width_val); - p.setPen(outline); - p.setBrush(Qt::NoBrush); - p.drawPath(path); - } + // draw outline + int outline_width_val = qCeil(outline_width->GetDoubleAt(timecode)); + if (outline_bool->GetBoolAt(timecode) && outline_width_val > 0) { + QPen outline(outline_color->GetColorAt(timecode)); + outline.setWidth(outline_width_val); + p.setPen(outline); + p.setBrush(Qt::NoBrush); + p.drawPath(path); + } - // draw "master" text - p.setPen(Qt::NoPen); - p.setBrush(set_color_button->get_color_value(timecode)); - p.drawPath(path); + // draw "master" text + p.setPen(Qt::NoPen); + p.setBrush(set_color_button->GetColorAt(timecode)); + p.drawPath(path); - p.end(); + p.end(); } void TextEffect::shadow_enable(bool e) { - close(); + close(); - shadow_color->set_enabled(e); - shadow_angle->set_enabled(e); - shadow_distance->set_enabled(e); - shadow_softness->set_enabled(e); - shadow_opacity->set_enabled(e); -} - -void TextEffect::text_edit_menu() { - QMenu menu; - - menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit())); - - menu.exec(QCursor::pos()); -} - -void TextEffect::open_text_edit() { - TextEditDialog ted(olive::MainWindow, text_val->get_current_data().toString()); - ted.exec(); - QString result = ted.get_string(); - if (!result.isEmpty()) { - text_val->set_current_data(result); - text_val->ui_element_change(); - } + shadow_color->SetEnabled(e); + shadow_angle->SetEnabled(e); + shadow_distance->SetEnabled(e); + shadow_softness->SetEnabled(e); + shadow_opacity->SetEnabled(e); } void TextEffect::outline_enable(bool e) { - outline_color->set_enabled(e); - outline_width->set_enabled(e); + outline_color->SetEnabled(e); + outline_width->SetEnabled(e); } diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index d73b60de0..c3d7734a6 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -27,36 +27,34 @@ #include class TextEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TextEffect(Clip* c, const EffectMeta *em); - void redraw(double timecode); + void redraw(double timecode); - EffectField* text_val; - EffectField* size_val; - EffectField* set_color_button; - EffectField* set_font_combobox; - EffectField* halign_field; - EffectField* valign_field; - EffectField* word_wrap_field; + StringField* text_val; + DoubleField* size_val; + ColorField* set_color_button; + FontField* set_font_combobox; + ComboField* halign_field; + ComboField* valign_field; + BoolField* word_wrap_field; - EffectField* outline_bool; - EffectField* outline_width; - EffectField* outline_color; + BoolField* outline_bool; + DoubleField* outline_width; + ColorField* outline_color; - EffectField* shadow_bool; - EffectField* shadow_angle; - EffectField* shadow_distance; - EffectField* shadow_color; - EffectField* shadow_softness; - EffectField* shadow_opacity; + BoolField* shadow_bool; + DoubleField* shadow_angle; + DoubleField* shadow_distance; + ColorField* shadow_color; + DoubleField* shadow_softness; + DoubleField* shadow_opacity; private slots: - void outline_enable(bool); - void shadow_enable(bool); - void text_edit_menu(); - void open_text_edit(); + void outline_enable(bool); + void shadow_enable(bool); private: - QFont font; + QFont font; }; #endif // TEXTEFFECT_H diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index b01e202d5..c69041954 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -46,45 +46,60 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - enable_always_update = true; - enable_superimpose = true; + SetAlwaysUpdate(true); + SetFlags(Effect::SuperimposeFlag); EffectRow* tc_row = add_row(tr("Timecode")); - tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector"); - tc_select->add_combo_item(tr("Sequence"), true); - tc_select->add_combo_item(tr("Media"), false); - tc_select->set_combo_index(0); + tc_select = new ComboField(tc_row, "tc_selector"); + tc_select->AddItem(tr("Sequence"), true); + tc_select->AddItem(tr("Media"), false); + tc_select->SetValueAt(0, true); - scale_val = add_row(tr("Scale"))->add_field(EFFECT_FIELD_DOUBLE, "scale", 2); - scale_val->set_double_minimum_value(1); - scale_val->set_double_default_value(100); - scale_val->set_double_maximum_value(1000); + EffectRow* scale_row = add_row(tr("Scale")); + scale_val = new DoubleField(scale_row, "scale"); + scale_val->SetColumnSpan(2); + scale_val->SetMinimum(1); + scale_val->SetDefault(100); + scale_val->SetMaximum(1000); - color_val = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2); - color_val->set_color_value(Qt::white); + EffectRow* color_row = add_row(tr("Color")); + color_val = new ColorField(color_row, "color"); + color_val->SetColumnSpan(2); + color_val->SetValueAt(0, QColor(Qt::white)); - color_bg_val = add_row(tr("Background Color"))->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2); - color_bg_val->set_color_value(Qt::black); + EffectRow* color_bg_row = add_row(tr("Background Color")); + color_bg_val = new ColorField(color_bg_row, "bgcolor"); + color_bg_val->SetColumnSpan(2); + color_bg_val->SetValueAt(0, QColor(Qt::black)); - bg_alpha = add_row(tr("Background Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2); - bg_alpha->set_double_minimum_value(0); - bg_alpha->set_double_maximum_value(100); - bg_alpha->set_double_default_value(50); + EffectRow* bg_alpha_row = add_row(tr("Background Opacity")); + bg_alpha = new DoubleField(bg_alpha_row, "bgalpha"); + bg_alpha->SetColumnSpan(2); + bg_alpha->SetMinimum(0); + bg_alpha->SetDefault(50); + bg_alpha->SetMaximum(100); - EffectRow* offset = add_row(tr("Offset")); - offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx"); - offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety"); + EffectRow* offset_row = add_row(tr("Offset")); + offset_x_val = new DoubleField(offset_row, "offsetx"); + offset_y_val = new DoubleField(offset_row, "offsety"); - prepend_text = add_row(tr("Prepend"))->add_field(EFFECT_FIELD_STRING, "prepend", 2); + EffectRow* prepent_text_row = add_row(tr("Prepend")); + prepend_text = new StringField(prepent_text_row, "prepend"); + prepend_text->SetColumnSpan(2); } void TimecodeEffect::redraw(double timecode) { - if (tc_select->get_combo_data(timecode).toBool()){ - display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate);} - else { + if (tc_select->GetValueAt(timecode).toBool()) { + display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, + olive::CurrentConfig.timecode_view, + olive::ActiveSequence->frame_rate); + } else { double media_rate = parent_clip->media_frame_rate(); - display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, olive::CurrentConfig.timecode_view, media_rate);} + display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(qRound(timecode * media_rate), + olive::CurrentConfig.timecode_view, + media_rate); + } img.fill(Qt::transparent); QPainter p(&img); @@ -95,7 +110,7 @@ void TimecodeEffect::redraw(double timecode) { // set font font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); font.setFamily("Helvetica"); - font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10))); + font.setPixelSize(qCeil(scale_val->GetDoubleAt(timecode)*.01*(height/10))); p.setFont(font); QFontMetrics fm(font); @@ -104,12 +119,12 @@ void TimecodeEffect::redraw(double timecode) { int text_x, text_y, rect_y, offset_x, offset_y; int text_height = fm.height(); int text_width = fm.width(display_timecode); - QColor background_color = color_bg_val->get_color_value(timecode); - int alpha_val = bg_alpha->get_double_value(timecode)*2.55; + 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->get_double_value(timecode)); - offset_y = int(offset_y_val->get_double_value(timecode)); + offset_x = int(offset_x_val->GetDoubleAt(timecode)); + offset_y = int(offset_y_val->GetDoubleAt(timecode)); text_x = offset_x + (width/2) - (text_width/2); text_y = offset_y + height - height/10; @@ -120,6 +135,6 @@ void TimecodeEffect::redraw(double timecode) { p.setPen(Qt::NoPen); p.setBrush(background_color); p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height)); - p.setBrush(color_val->get_color_value(timecode)); + p.setBrush(color_val->GetColorAt(timecode)); p.drawPath(path); } diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h index 2caeb3276..1e8ba5ec8 100644 --- a/effects/internal/timecodeeffect.h +++ b/effects/internal/timecodeeffect.h @@ -27,18 +27,18 @@ #include class TimecodeEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TimecodeEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); - EffectField * scale_val; - EffectField * color_val; - EffectField * color_bg_val; - EffectField * bg_alpha; - EffectField * offset_x_val; - EffectField * offset_y_val; - EffectField * prepend_text; - EffectField * tc_select; + 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; private: QFont font; diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index 777c3e878..132112a98 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -29,44 +29,50 @@ #include "debug.h" ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { - type_val = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type"); - type_val->add_combo_item("Sine", TONE_TYPE_SINE); + EffectRow* type_row = add_row(tr("Type")); + type_val = new ComboField(type_row, "type"); + type_val->AddItem(tr("Sine"), TONE_TYPE_SINE); - freq_val = add_row(tr("Frequency"))->add_field(EFFECT_FIELD_DOUBLE, "frequency"); - freq_val->set_double_minimum_value(20); - freq_val->set_double_maximum_value(20000); - freq_val->set_double_default_value(1000); + EffectRow* frequency_row = add_row(tr("Frequency")); + freq_val = new DoubleField(frequency_row, "frequency"); + freq_val->SetMinimum(20); + freq_val->SetMaximum(20000); + freq_val->SetDefault(1000); - amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount"); - amount_val->set_double_minimum_value(0); - amount_val->set_double_maximum_value(100); - amount_val->set_double_default_value(25); + EffectRow* amount_row = add_row(tr("Amount")); + amount_val = new DoubleField(amount_row, "amount"); + amount_val->SetMinimum(0); + amount_val->SetMaximum(100); + amount_val->SetDefault(25); - mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix"); - mix_val->set_bool_value(true); + EffectRow* mix_row = add_row(tr("Mix")); + mix_val = new BoolField(mix_row, "mix"); + mix_val->SetValueAt(0, true); } void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) { - double interval = (timecode_end - timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode, true))/parent_clip->sequence->audio_frequency)*log_volume(amount_val->get_double_value(timecode, true)*0.01)*INT16_MAX)); - qint16 right_tone_sample = left_tone_sample; + qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode)) + /parent_clip->sequence->audio_frequency) + *log_volume(amount_val->GetDoubleAt(timecode)*0.01)*INT16_MAX)); + qint16 right_tone_sample = left_tone_sample; - // mix with source audio - if (mix_val->get_bool_value(timecode, true)) { - qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - left_tone_sample = mix_audio_sample(left_tone_sample, left_sample); - right_tone_sample = mix_audio_sample(right_tone_sample, right_sample); - } + // mix with source audio + if (mix_val->GetBoolAt(timecode)) { + qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + left_tone_sample = mix_audio_sample(left_tone_sample, left_sample); + right_tone_sample = mix_audio_sample(right_tone_sample, right_sample); + } - samples[i+3] = quint8(right_tone_sample >> 8); - samples[i+2] = quint8(right_tone_sample); - samples[i+1] = quint8(left_tone_sample >> 8); - samples[i] = quint8(left_tone_sample); + samples[i+3] = quint8(right_tone_sample >> 8); + samples[i+2] = quint8(right_tone_sample); + samples[i+1] = quint8(left_tone_sample >> 8); + samples[i] = quint8(left_tone_sample); - sinX++; - } + sinX++; + } } diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h index 2007ac70e..2b0223e47 100644 --- a/effects/internal/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -24,17 +24,17 @@ #include "project/effect.h" class ToneEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - ToneEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + ToneEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* type_val; - EffectField* freq_val; - EffectField* amount_val; - EffectField* mix_val; + ComboField* type_val; + DoubleField* freq_val; + DoubleField* amount_val; + BoolField* mix_val; private: - int sinX; + int sinX; }; #endif // TONEEFFECT_H diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 07dd08d3f..0662bc0d1 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -44,230 +44,197 @@ #include "ui/viewerwidget.h" TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - enable_coords = true; + SetFlags(Effect::CoordsFlag); - EffectRow* position_row = add_row(tr("Position")); - position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X - position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y + EffectRow* position_row = add_row(tr("Position")); - EffectRow* scale_row = add_row(tr("Scale")); - scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected) - scale_x->set_double_minimum_value(0); - scale_x->set_double_maximum_value(3000); - scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected) - scale_y->set_double_minimum_value(0); - scale_y->set_double_maximum_value(3000); + position_x = new DoubleField(position_row, "posx"); // position X + position_y = new DoubleField(position_row, "posy"); // position Y - EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); - uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option + EffectRow* scale_row = add_row(tr("Scale")); - EffectRow* rotation_row = add_row(tr("Rotation")); - rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); + // scale X (and Y is uniform scale is selected) + scale_x = new DoubleField(scale_row, "scalex"); + scale_x->SetMinimum(0); - EffectRow* anchor_point_row = add_row(tr("Anchor Point")); - anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X - anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y + // scale Y (disabled if uniform scale is selected) + scale_y = new DoubleField(scale_row, "scaley"); + scale_y->SetMinimum(0); - EffectRow* opacity_row = add_row(tr("Opacity")); - opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity - opacity->set_double_minimum_value(0); - opacity->set_double_maximum_value(100); + EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); - EffectRow* blend_mode_row = add_row(tr("Blend Mode")); - blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode", 2); // blend mode - blend_mode_box->add_combo_item(tr("Normal"), BLEND_MODE_NORMAL); - blend_mode_box->add_combo_item(tr("Darken"), BLEND_MODE_DARKEN); - blend_mode_box->add_combo_item(tr("Multiply"), BLEND_MODE_MULTIPLY); - blend_mode_box->add_combo_item(tr("Color Burn"), BLEND_MODE_COLORBURN); - blend_mode_box->add_combo_item(tr("Linear Burn"), BLEND_MODE_LINEARBURN); - blend_mode_box->add_combo_item(tr("Lighten"), BLEND_MODE_LIGHTEN); - blend_mode_box->add_combo_item(tr("Screen"), BLEND_MODE_SCREEN); - blend_mode_box->add_combo_item(tr("Color Dodge"), BLEND_MODE_COLORDODGE); - blend_mode_box->add_combo_item(tr("Linear Dodge (Add)"), BLEND_MODE_LINEARDODGE); - blend_mode_box->add_combo_item(tr("Overlay"), BLEND_MODE_OVERLAY); - blend_mode_box->add_combo_item(tr("Soft Light"), BLEND_MODE_SOFTLIGHT); - blend_mode_box->add_combo_item(tr("Hard Light"), BLEND_MODE_HARDLIGHT); - blend_mode_box->add_combo_item(tr("Vivid Light"), BLEND_MODE_VIVIDLIGHT); - blend_mode_box->add_combo_item(tr("Linear Light"), BLEND_MODE_LINEARLIGHT); - blend_mode_box->add_combo_item(tr("Pin Light"), BLEND_MODE_PINLIGHT); - blend_mode_box->add_combo_item(tr("Hard Mix"), BLEND_MODE_HARDMIX); - blend_mode_box->add_combo_item(tr("Difference"), BLEND_MODE_DIFFERENCE); - blend_mode_box->add_combo_item(tr("Exclusion"), BLEND_MODE_EXCLUSION); - blend_mode_box->add_combo_item(tr("Reflect"), BLEND_MODE_REFLECT); -// blend_mode_box->add_combo_item(tr("Subtract"), BLEND_MODE_SUBTRACT); - blend_mode_box->add_combo_item(tr("Substract"), BLEND_MODE_SUBSTRACT); -// blend_mode_box->add_combo_item(tr("Add"), BLEND_MODE_ADD); - blend_mode_box->add_combo_item(tr("Average"), BLEND_MODE_AVERAGE); - blend_mode_box->add_combo_item(tr("Glow"), BLEND_MODE_GLOW); - blend_mode_box->add_combo_item(tr("Negation"), BLEND_MODE_NEGATION); - blend_mode_box->add_combo_item(tr("Phoenix"), BLEND_MODE_PHOENIX); + uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option - // 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; + EffectRow* rotation_row = add_row(tr("Rotation")); - top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_center_gizmo->set_cursor(Qt::SizeVerCursor); - top_center_gizmo->y_field1 = scale_x; + rotation = new DoubleField(rotation_row, "rotation"); - top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); - top_right_gizmo->x_field1 = scale_x; + EffectRow* anchor_point_row = add_row(tr("Anchor Point")); - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); - bottom_left_gizmo->x_field1 = scale_x; + anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X + anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y - bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); - bottom_center_gizmo->y_field1 = scale_x; + EffectRow* opacity_row = add_row(tr("Opacity")); - bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); - bottom_right_gizmo->x_field1 = scale_x; + // opacity + opacity = new DoubleField(opacity_row, "opacity"); + opacity->SetMinimum(0); + opacity->SetMaximum(100); - left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - left_center_gizmo->set_cursor(Qt::SizeHorCursor); - left_center_gizmo->x_field1 = scale_x; + EffectRow* blend_mode_row = add_row(tr("Blend Mode")); - right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - right_center_gizmo->set_cursor(Qt::SizeHorCursor); - right_center_gizmo->x_field1 = scale_x; + // blend mode + blend_mode_box = new ComboField(blend_mode_row, "blendmode"); + blend_mode_box->SetColumnSpan(2); + blend_mode_box->AddItem(tr("Normal"), ""); - 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; + // 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; - rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); - rotate_gizmo->color = Qt::green; - rotate_gizmo->set_cursor(Qt::SizeAllCursor); - rotate_gizmo->x_field1 = rotation; + top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_center_gizmo->set_cursor(Qt::SizeVerCursor); + top_center_gizmo->y_field1 = scale_x; - rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); - rect_gizmo->x_field1 = position_x; - rect_gizmo->y_field1 = position_y; + top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); + top_right_gizmo->x_field1 = scale_x; - connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); + bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); + bottom_left_gizmo->x_field1 = scale_x; - // set defaults - uniform_scale_field->set_bool_value(true); - blend_mode_box->set_combo_index(0); - set = false; - refresh(); -} + bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); + bottom_center_gizmo->y_field1 = scale_x; -void adjust_field(EffectField* field, double old_offset, double new_offset) { - if (field->keyframes.size() > 0) { - for (int i=0;ikeyframes.size();i++) { - field->keyframes[i].data = field->keyframes.at(i).data.toDouble() - old_offset + new_offset; - } - } else { - field->set_current_data(field->get_current_data().toDouble() - old_offset + new_offset); - } + bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); + bottom_right_gizmo->x_field1 = scale_x; + + left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + left_center_gizmo->set_cursor(Qt::SizeHorCursor); + left_center_gizmo->x_field1 = scale_x; + + right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + right_center_gizmo->set_cursor(Qt::SizeHorCursor); + right_center_gizmo->x_field1 = scale_x; + + 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; + + rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); + rotate_gizmo->color = Qt::green; + rotate_gizmo->set_cursor(Qt::SizeAllCursor); + rotate_gizmo->x_field1 = rotation; + + rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); + rect_gizmo->x_field1 = position_x; + rect_gizmo->y_field1 = position_y; + + 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, ""); + 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->sequence != nullptr) { - double new_default_pos_x = parent_clip->sequence->width/2; - double new_default_pos_y = parent_clip->sequence->height/2; + if (parent_clip != nullptr && parent_clip->sequence != nullptr) { - /*if (set) { - adjust_field(position_x, default_pos_x, new_default_pos_x); - adjust_field(position_y, default_pos_y, new_default_pos_y); - }*/ + position_x->SetDefault(parent_clip->sequence->width/2); + position_y->SetDefault(parent_clip->sequence->height/2); - double default_pos_x = new_default_pos_x; - double default_pos_y = new_default_pos_y; + double x_percent_multipler = 200.0 / parent_clip->sequence->width; + double y_percent_multipler = 200.0 / parent_clip->sequence->height; - position_x->set_double_default_value(default_pos_x); - position_y->set_double_default_value(default_pos_y); - scale_x->set_double_default_value(100); - scale_y->set_double_default_value(100); + top_left_gizmo->x_field_multi1 = -x_percent_multipler; + top_left_gizmo->y_field_multi1 = -y_percent_multipler; + top_center_gizmo->y_field_multi1 = -y_percent_multipler; + top_right_gizmo->x_field_multi1 = x_percent_multipler; + top_right_gizmo->y_field_multi1 = -y_percent_multipler; + bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; + bottom_left_gizmo->y_field_multi1 = y_percent_multipler; + bottom_center_gizmo->y_field_multi1 = y_percent_multipler; + bottom_right_gizmo->x_field_multi1 = x_percent_multipler; + bottom_right_gizmo->y_field_multi1 = y_percent_multipler; + left_center_gizmo->x_field_multi1 = -x_percent_multipler; + right_center_gizmo->x_field_multi1 = x_percent_multipler; + rotate_gizmo->x_field_multi1 = x_percent_multipler; - anchor_x_box->set_double_default_value(0); - anchor_y_box->set_double_default_value(0); - opacity->set_double_default_value(100); - - double x_percent_multipler = 200.0 / parent_clip->sequence->width; - double y_percent_multipler = 200.0 / parent_clip->sequence->height; - top_left_gizmo->x_field_multi1 = -x_percent_multipler; - top_left_gizmo->y_field_multi1 = -y_percent_multipler; - top_center_gizmo->y_field_multi1 = -y_percent_multipler; - top_right_gizmo->x_field_multi1 = x_percent_multipler; - top_right_gizmo->y_field_multi1 = -y_percent_multipler; - bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; - bottom_left_gizmo->y_field_multi1 = y_percent_multipler; - bottom_center_gizmo->y_field_multi1 = y_percent_multipler; - bottom_right_gizmo->x_field_multi1 = x_percent_multipler; - bottom_right_gizmo->y_field_multi1 = y_percent_multipler; - left_center_gizmo->x_field_multi1 = -x_percent_multipler; - right_center_gizmo->x_field_multi1 = x_percent_multipler; - rotate_gizmo->x_field_multi1 = x_percent_multipler; - - set = true; - } + } } void TransformEffect::toggle_uniform_scale(bool enabled) { - scale_y->set_enabled(!enabled); + scale_y->SetEnabled(!enabled); - top_center_gizmo->y_field1 = enabled ? scale_x : scale_y; - bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y; - top_left_gizmo->y_field1 = enabled ? nullptr : scale_y; - top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; + top_center_gizmo->y_field1 = enabled ? scale_x : scale_y; + bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y; + top_left_gizmo->y_field1 = enabled ? nullptr : scale_y; + top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; + bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; + bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; } void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - // position - glTranslated(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0); + // position + glTranslated(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), + position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), + 0); - // anchor point - int anchor_x_offset = qRound(anchor_x_box->get_double_value(timecode)); - int anchor_y_offset = qRound(anchor_y_box->get_double_value(timecode)); - coords.vertexTopLeftX -= anchor_x_offset; - coords.vertexTopRightX -= anchor_x_offset; - coords.vertexBottomLeftX -= anchor_x_offset; - coords.vertexBottomRightX -= anchor_x_offset; - coords.vertexTopLeftY -= anchor_y_offset; - coords.vertexTopRightY -= anchor_y_offset; - coords.vertexBottomLeftY -= anchor_y_offset; - coords.vertexBottomRightY -= anchor_y_offset; + // anchor point + int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); + int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode)); + coords.vertexTopLeftX -= anchor_x_offset; + coords.vertexTopRightX -= anchor_x_offset; + coords.vertexBottomLeftX -= anchor_x_offset; + coords.vertexBottomRightX -= anchor_x_offset; + coords.vertexTopLeftY -= anchor_y_offset; + coords.vertexTopRightY -= anchor_y_offset; + coords.vertexBottomLeftY -= anchor_y_offset; + coords.vertexBottomRightY -= anchor_y_offset; - // rotation - glRotated(rotation->get_double_value(timecode), 0, 0, 1); + // rotation + glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1); - // scale - double sx = scale_x->get_double_value(timecode)*0.01; - double sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01; - glScaled(sx, sy, 1); + // scale + double sx = scale_x->GetDoubleAt(timecode)*0.01; + double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01; + glScaled(sx, sy, 1); - // blend mode - coords.blendmode = blend_mode_box->get_combo_data(timecode).toInt(); + // blend mode + coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt(); - // opacity - coords.opacity *= float(opacity->get_double_value(timecode)*0.01); + // opacity + coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01); } void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); - left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); + top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); + top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); + bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); + bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); - rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); + rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); - rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); } diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h index f815659ed..13b007bc0 100644 --- a/effects/internal/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -24,40 +24,38 @@ #include "project/effect.h" class TransformEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TransformEffect(Clip* c, const EffectMeta* em); - void refresh(); - void process_coords(double timecode, GLTextureCoords& coords, int data); + void refresh(); + void process_coords(double timecode, GLTextureCoords& coords, int data); - void gizmo_draw(double timecode, GLTextureCoords& coords); + void gizmo_draw(double timecode, GLTextureCoords& coords); public slots: - void toggle_uniform_scale(bool enabled); + void toggle_uniform_scale(bool enabled); private: - EffectField* position_x; - EffectField* position_y; - EffectField* scale_x; - EffectField* scale_y; - EffectField* uniform_scale_field; - EffectField* rotation; - EffectField* anchor_x_box; - EffectField* anchor_y_box; - EffectField* opacity; - EffectField* blend_mode_box; + 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; - EffectGizmo* top_left_gizmo; - EffectGizmo* top_center_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_center_gizmo; - EffectGizmo* bottom_right_gizmo; - EffectGizmo* left_center_gizmo; - EffectGizmo* right_center_gizmo; - EffectGizmo* anchor_gizmo; - EffectGizmo* rotate_gizmo; - EffectGizmo* rect_gizmo; - - bool set; + EffectGizmo* top_left_gizmo; + EffectGizmo* top_center_gizmo; + EffectGizmo* top_right_gizmo; + EffectGizmo* bottom_left_gizmo; + EffectGizmo* bottom_center_gizmo; + EffectGizmo* bottom_right_gizmo; + EffectGizmo* left_center_gizmo; + EffectGizmo* right_center_gizmo; + EffectGizmo* anchor_gizmo; + EffectGizmo* rotate_gizmo; + EffectGizmo* rect_gizmo; }; #endif // TRANSFORMEFFECT_H diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index 23cf1a45f..a08427a41 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -29,41 +29,40 @@ #include "ui/collapsiblewidget.h" VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* volume_row = add_row(tr("Volume")); - volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume"); + EffectRow* volume_row = add_row(tr("Volume")); + volume_val = new DoubleField(volume_row, "volume"); - // set defaults - volume_val->set_double_default_value(1); - static_cast(volume_val->get_ui_element())->set_display_type(LABELSLIDER_DECIBEL); + // set defaults + volume_val->SetDefault(1); + volume_val->SetDisplayType(LabelSlider::LABELSLIDER_DECIBEL); } void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end-timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode_start+(interval*i), true)); - double vol_val = volume_val->get_double_value(timecode_start+(interval*i), true); + double interval = (timecode_end-timecode_start)/nb_bytes; + for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); - qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - left_samp *= vol_val; - right_samp *= vol_val; + left_samp *= vol_val; + right_samp *= vol_val; - if (left_samp > INT16_MAX) { - left_samp = INT16_MAX; - } else if (left_samp < INT16_MIN) { - left_samp = INT16_MIN; - } + if (left_samp > INT16_MAX) { + left_samp = INT16_MAX; + } else if (left_samp < INT16_MIN) { + left_samp = INT16_MIN; + } - if (right_samp > INT16_MAX) { - right_samp = INT16_MAX; - } else if (right_samp < INT16_MIN) { - right_samp = INT16_MIN; - } + if (right_samp > INT16_MAX) { + right_samp = INT16_MAX; + } else if (right_samp < INT16_MIN) { + right_samp = INT16_MIN; + } - samples[i+3] = (quint8) (right_samp >> 8); - samples[i+2] = (quint8) right_samp; - samples[i+1] = (quint8) (left_samp >> 8); - samples[i] = (quint8) left_samp; - } + samples[i+3] = (quint8) (right_samp >> 8); + samples[i+2] = (quint8) right_samp; + samples[i+1] = (quint8) (left_samp >> 8); + samples[i] = (quint8) left_samp; + } } diff --git a/effects/internal/volumeeffect.h b/effects/internal/volumeeffect.h index 6d143f5af..584c6c00c 100644 --- a/effects/internal/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class VolumeEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - VolumeEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + VolumeEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* volume_val; + DoubleField* volume_val; }; #endif // VOLUMEEFFECT_H diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index 89fa02cdc..aa38f2470 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -106,7 +106,7 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events); typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames); void VSTHost::loadPlugin() { - QString dll_fn = file_field->get_filename(0, true); + QString dll_fn = file_field->GetFileAt(0); if (dll_fn.isEmpty()) { return; @@ -266,7 +266,8 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) { outputs[channel] = new float[BLOCK_SIZE]; } - file_field = add_row(tr("Plugin"), true, false)->add_field(EFFECT_FIELD_FILE, "filename"); + EffectRow* file_row = add_row(tr("Plugin"), true, false); + file_field = new FileField(file_row, "filename"); connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin())); EffectRow* interface_row = add_row(tr("Interface"), false, false); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index cd2d2ae48..cebd2e11d 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -35,42 +35,42 @@ typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t i #include class VSTHost : public Effect { - Q_OBJECT + Q_OBJECT public: VSTHost(Clip* c, const EffectMeta* em); - ~VSTHost(); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + ~VSTHost(); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - void custom_load(QXmlStreamReader& stream); - void save(QXmlStreamWriter& stream); + void custom_load(QXmlStreamReader& stream); + void save(QXmlStreamWriter& stream); private slots: - void show_interface(bool show); - void uncheck_show_button(); - void change_plugin(); + void show_interface(bool show); + void uncheck_show_button(); + void change_plugin(); private: - EffectField* file_field; + FileField* file_field; - void loadPlugin(); - void freePlugin(); - dispatcherFuncPtr dispatcher; - AEffect* plugin; - bool configurePluginCallbacks(); - void startPlugin(); - void stopPlugin(); - void resumePlugin(); - void suspendPlugin(); - bool canPluginDo(char *canDoString); - void processAudio(long numFrames); - float** inputs; - float** outputs; - QDialog* dialog; - QPushButton* show_interface_btn; - QByteArray data_cache; + void loadPlugin(); + void freePlugin(); + dispatcherFuncPtr dispatcher; + AEffect* plugin; + bool configurePluginCallbacks(); + void startPlugin(); + void stopPlugin(); + void resumePlugin(); + void suspendPlugin(); + bool canPluginDo(char *canDoString); + void processAudio(long numFrames); + float** inputs; + float** outputs; + QDialog* dialog; + QPushButton* show_interface_btn; + QByteArray data_cache; #if defined(__APPLE__) - CFBundleRef bundle; + CFBundleRef bundle; #else - ModulePtr modulePtr; + ModulePtr modulePtr; #endif }; diff --git a/olive.pro b/olive.pro index 5f844a844..a826f8380 100644 --- a/olive.pro +++ b/olive.pro @@ -116,8 +116,6 @@ SOURCES += \ project/effect.cpp \ project/transition.cpp \ project/effectrow.cpp \ - project/effectfield.cpp \ - effects/internal/cubetransition.cpp \ project/effectgizmo.cpp \ io/clipboard.cpp \ ui/resizablescrollbar.cpp \ @@ -162,7 +160,15 @@ SOURCES += \ dialogs/clippropertiesdialog.cpp \ rendering/framebufferobject.cpp \ ui/updatenotification.cpp \ - ui/icons.cpp + ui/icons.cpp \ + project/effectfields/doublefield.cpp \ + project/effectfields/fontfield.cpp \ + project/effectfields/effectfield.cpp \ + project/effectfields/colorfield.cpp \ + project/effectfields/stringfield.cpp \ + project/effectfields/boolfield.cpp \ + project/effectfields/combofield.cpp \ + project/effectfields/filefield.cpp HEADERS += \ mainwindow.h \ @@ -229,7 +235,6 @@ HEADERS += \ project/effect.h \ project/transition.h \ project/effectrow.h \ - project/effectfield.h \ effects/internal/cubetransition.h \ project/effectgizmo.h \ io/clipboard.h \ @@ -276,7 +281,16 @@ HEADERS += \ dialogs/clippropertiesdialog.h \ rendering/framebufferobject.h \ ui/updatenotification.h \ - ui/icons.h + ui/icons.h \ + project/effectfields/doublefield.h \ + project/effectfields/fontfield.h \ + project/effectfields/effectfield.h \ + project/effectfields.h \ + project/effectfields/colorfield.h \ + project/effectfields/stringfield.h \ + project/effectfields/boolfield.h \ + project/effectfields/combofield.h \ + project/effectfields/filefield.h FORMS += diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index bd0494389..4f5806aaf 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -31,9 +31,10 @@ #include "ui/labelslider.h" #include "ui/graphview.h" #include "project/effect.h" -#include "project/effectfield.h" +#include "project/effectfields.h" #include "project/effectrow.h" #include "project/clip.h" +#include "rendering/renderfunctions.h" #include "panels.h" #include "debug.h" @@ -142,8 +143,12 @@ void GraphEditor::update_panel() { int slider_index = 0; for (int i=0;ifieldCount();i++) { EffectField* field = row->field(i); - if (field->type == EFFECT_FIELD_DOUBLE) { - slider_proxies.at(slider_index)->set_value(row->field(i)->get_current_data().toDouble(), false); + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { + slider_proxies.at(slider_index)->set_value( + row->field(i)->GetValueAt(playhead_to_clip_seconds(field->GetParentRow()->parent_effect->parent_clip, + olive::ActiveSequence->playhead)).toDouble(), + false + ); slider_index++; } } @@ -175,10 +180,10 @@ 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 == EFFECT_FIELD_DOUBLE) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { QPushButton* slider_button = new QPushButton(); slider_button->setCheckable(true); - slider_button->setChecked(field->is_enabled()); + slider_button->setChecked(field->IsEnabled()); slider_button->setIcon(QIcon(":/icons/record.svg")); slider_button->setProperty("field", i); slider_button->setIconSize(slider_button->iconSize()*0.5); @@ -192,7 +197,7 @@ void GraphEditor::set_row(EffectRow *r) { slider_proxies.append(slider); value_layout->addWidget(slider); - slider_proxy_sources.append(static_cast(field->ui_element)); + //slider_proxy_sources.append(static_cast(field->ui_element)); found_vals = true; } @@ -203,7 +208,7 @@ void GraphEditor::set_row(EffectRow *r) { row = r; current_row_desc->setText(row->parent_effect->parent_clip->name() + " :: " + row->parent_effect->meta->name - + " :: " + row->get_name()); + + " :: " + row->name()); header->set_visible_in(r->parent_effect->parent_clip->timeline_in()); connect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(goto_previous_key())); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index e857185d3..c6455b347 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -82,7 +82,7 @@ Viewer::Viewer(QWidget *parent) : current_timecode_slider->set_minimum_value(0); current_timecode_slider->set_default_value(qSNaN()); current_timecode_slider->set_value(0, false); - current_timecode_slider->set_display_type(LABELSLIDER_FRAMENUMBER); + current_timecode_slider->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); connect(current_timecode_slider, SIGNAL(valueChanged()), this, SLOT(update_playhead())); recording_flasher.setInterval(500); diff --git a/project/clip.cpp b/project/clip.cpp index f40508b4b..aaf532da3 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -574,8 +574,8 @@ bool Clip::Retrieve() int frame_size = frame->linesize[0]*frame->height; for (int i=0;ienable_image && e->is_enabled()) { + Effect* e = effects.at(i).get(); + if ((e->Flags() & Effect::ImageFlag) && e->is_enabled()) { if (data_buffer_1 == frame->data[0]) { data_buffer_1 = new uint8_t[frame_size]; data_buffer_2 = new uint8_t[frame_size]; diff --git a/project/effect.cpp b/project/effect.cpp index a49ae6977..a437bf125 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -70,871 +70,897 @@ QVector effects; EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { - if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { - // must be an internal effect - switch (em->internal) { - case EFFECT_INTERNAL_TRANSFORM: return EffectPtr(new TransformEffect(c, em)); - case EFFECT_INTERNAL_TEXT: return EffectPtr(new TextEffect(c, em)); - case EFFECT_INTERNAL_TIMECODE: return EffectPtr(new TimecodeEffect(c, em)); - case EFFECT_INTERNAL_SOLID: return EffectPtr(new SolidEffect(c, em)); - case EFFECT_INTERNAL_NOISE: return EffectPtr(new AudioNoiseEffect(c, em)); - case EFFECT_INTERNAL_VOLUME: return EffectPtr(new VolumeEffect(c, em)); - case EFFECT_INTERNAL_PAN: return EffectPtr(new PanEffect(c, em)); - case EFFECT_INTERNAL_TONE: return EffectPtr(new ToneEffect(c, em)); - case EFFECT_INTERNAL_SHAKE: return EffectPtr(new ShakeEffect(c, em)); - case EFFECT_INTERNAL_CORNERPIN: return EffectPtr(new CornerPinEffect(c, em)); - case EFFECT_INTERNAL_FILLLEFTRIGHT: return EffectPtr(new FillLeftRightEffect(c, em)); + if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { + // must be an internal effect + switch (em->internal) { + case EFFECT_INTERNAL_TRANSFORM: return std::make_shared(c, em); + case EFFECT_INTERNAL_TEXT: return std::make_shared(c, em); + case EFFECT_INTERNAL_TIMECODE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SOLID: return std::make_shared(c, em); + case EFFECT_INTERNAL_NOISE: return std::make_shared(c, em); + case EFFECT_INTERNAL_VOLUME: return std::make_shared(c, em); + case EFFECT_INTERNAL_PAN: return std::make_shared(c, em); + case EFFECT_INTERNAL_TONE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SHAKE: return std::make_shared(c, em); + case EFFECT_INTERNAL_CORNERPIN: return std::make_shared(c, em); + case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared(c, em); #ifndef NOVST - case EFFECT_INTERNAL_VST: return EffectPtr(new VSTHost(c, em)); + case EFFECT_INTERNAL_VST: return std::make_shared(c, em); #endif #ifndef NOFREI0R - case EFFECT_INTERNAL_FREI0R: return EffectPtr(new Frei0rEffect(c, em)); + case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); #endif - } - } else if (!em->filename.isEmpty()) { - // load effect from file - return EffectPtr(new Effect(c, em)); - } else { - qCritical() << "Invalid effect data"; + } + } else if (!em->filename.isEmpty()) { + // load effect from file + return std::make_shared(c, em); + } else { + qCritical() << "Invalid effect data"; QMessageBox::critical(olive::MainWindow, - QCoreApplication::translate("Effect", "Invalid effect"), - QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); - } - return nullptr; + QCoreApplication::translate("Effect", "Invalid effect"), + QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); + } + return nullptr; } const EffectMeta* Effect::GetInternalMeta(int internal_id, int type) { - for (int i=0;ienabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); - ui = new QWidget(container); - ui_layout = new QGridLayout(ui); - ui_layout->setSpacing(4); - container->setContents(ui); + // set up base UI + container = new CollapsibleWidget(); + connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); + ui = new QWidget(container); + ui_layout = new QGridLayout(ui); + ui_layout->setSpacing(4); + container->setContents(ui); - connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); + connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); - if (em != nullptr) { - // set up UI from effect file - container->setText(em->name); + if (em != nullptr) { + // set up UI from effect file + container->setText(em->name); - if (!em->filename.isEmpty() && em->internal == -1) { - QFile effect_file(em->filename); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); + if (!em->filename.isEmpty() && em->internal == -1) { + QFile effect_file(em->filename); + if (effect_file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&effect_file); - while (!reader.atEnd()) { - if (reader.name() == "row" && reader.isStartElement()) { - QString row_name; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename << "- ID cannot be empty."; - } else if (type > -1) { - EffectField* field = row->add_field(type, id); - connect(field, SIGNAL(changed()), this, SLOT(field_changed())); - switch (type) { - case EFFECT_FIELD_DOUBLE: - for (int i=0;iset_double_default_value(attr.value().toDouble()); - } else if (attr.name() == "min") { - field->set_double_minimum_value(attr.value().toDouble()); - } else if (attr.name() == "max") { - field->set_double_maximum_value(attr.value().toDouble()); - } - } - break; - case EFFECT_FIELD_COLOR: - { - QColor color; - for (int i=0;iset_color_value(color); - } - break; - case EFFECT_FIELD_STRING: - for (int i=0;iset_string_value(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_BOOL: - for (int i=0;iset_bool_value(attr.value() == "1"); - } - } - break; - case EFFECT_FIELD_COMBO: - { - int combo_index = 0; - for (int i=0;iadd_combo_item(reader.text().toString(), 0); - } - } - field->set_combo_index(combo_index); - } - break; - case EFFECT_FIELD_FONT: - for (int i=0;iset_font_name(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_FILE: - for (int i=0;iset_filename(attr.value().toString()); - } - } - break; - } - } - } - } - } - } else if (reader.name() == "shader" && reader.isStartElement()) { - enable_shader = true; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename; - enable_superimpose = false; - } - break; - } - } - }*/ - reader.readNext(); - } + if (id.isEmpty()) { + qCritical() << "Couldn't load field from" << em->filename << "- ID cannot be empty."; + } else { + EffectField* field = nullptr; - effect_file.close(); - } else { - qCritical() << "Failed to open effect file" << em->filename; - } - } - } + switch (type) { + case EffectField::EFFECT_FIELD_DOUBLE: + { + + 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 EffectField::EFFECT_FIELD_COLOR: + { + QColor color; + + field = new ColorField(row, id); + + for (int i=0;iSetValueAt(0, color); + } + break; + case EffectField::EFFECT_FIELD_STRING: + field = new StringField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + case EffectField::EFFECT_FIELD_BOOL: + field = new BoolField(row, id); + for (int i=0;iSetValueAt(0, attr.value() == "1"); + } + } + break; + case EffectField::EFFECT_FIELD_COMBO: + { + 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 EffectField::EFFECT_FIELD_FONT: + field = new FontField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + case EffectField::EFFECT_FIELD_FILE: + field = new FileField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + } + + if (field != nullptr) { + connect(field, SIGNAL(changed()), this, SLOT(field_changed())); + } + } + } + } + } + } else if (reader.name() == "shader" && reader.isStartElement()) { + SetFlags(Flags() & ShaderFlag); + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;ifilename; + enable_superimpose = false; + } + break; + } + } + }*/ + reader.readNext(); + } + + effect_file.close(); + } else { + qCritical() << "Failed to open effect file" << em->filename; + } + } + } } Effect::~Effect() { - if (isOpen) { - close(); - } + if (isOpen) { + close(); + } - delete container; + delete container; - for (int i=0;irows.at(i); - copy_row->setKeyframing(row->isKeyframing()); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - EffectField* copy_field = copy_row->field(j); - copy_field->keyframes = field->keyframes; - copy_field->set_current_data(field->get_current_data()); - } - } + for (int i=0;irows.at(i); + copy_row->setKeyframing(row->isKeyframing()); + for (int j=0;jfieldCount();j++) { + // Get field from this (the source) effect + EffectField* field = row->field(j); + + // Get field from the destination effect + EffectField* copy_field = copy_row->field(j); + + // Copy keyframes between effects + copy_field->keyframes = field->keyframes; + } + } } EffectRow* Effect::add_row(const QString& name, bool savable, bool keyframable) { - EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); - rows.append(row); - return row; + EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); + rows.append(row); + return row; } EffectRow* Effect::row(int i) { - return rows.at(i); + return rows.at(i); } int Effect::row_count() { - return rows.size(); + return rows.size(); } EffectGizmo *Effect::add_gizmo(int type) { - EffectGizmo* gizmo = new EffectGizmo(type); - gizmos.append(gizmo); - return gizmo; + EffectGizmo* gizmo = new EffectGizmo(type); + gizmos.append(gizmo); + return gizmo; } EffectGizmo *Effect::gizmo(int i) { - return gizmos.at(i); + return gizmos.at(i); } int Effect::gizmo_count() { - return gizmos.size(); + return gizmos.size(); } void Effect::refresh() {} void Effect::field_changed() { - panel_sequence_viewer->viewer_widget->frame_update(); - panel_graph_editor->update_panel(); + panel_sequence_viewer->viewer_widget->frame_update(); + panel_graph_editor->update_panel(); } void Effect::show_context_menu(const QPoint& pos) { - if (meta->type == EFFECT_TYPE_EFFECT) { + if (meta->type == EFFECT_TYPE_EFFECT) { QMenu menu(olive::MainWindow); - int index = get_index_in_clip(); + int index = get_index_in_clip(); - menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); - menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); + menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); + menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); - panel_effect_controls->add_effect_paste_action(&menu); + panel_effect_controls->add_effect_paste_action(&menu); - menu.addSeparator(); + menu.addSeparator(); - if (index > 0) { - menu.addAction(tr("Move &Up"), this, SLOT(move_up())); - } + if (index > 0) { + menu.addAction(tr("Move &Up"), this, SLOT(move_up())); + } - if (index < parent_clip->effects.size() - 1) { - menu.addAction(tr("Move &Down"), this, SLOT(move_down())); - } + if (index < parent_clip->effects.size() - 1) { + menu.addAction(tr("Move &Down"), this, SLOT(move_down())); + } - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("D&elete"), this, SLOT(delete_self())); + menu.addAction(tr("D&elete"), this, SLOT(delete_self())); - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); + menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); - menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); + menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); - menu.exec(container->title_bar->mapToGlobal(pos)); - } + menu.exec(container->title_bar->mapToGlobal(pos)); + } } void Effect::delete_self() { - EffectDeleteCommand* command = new EffectDeleteCommand(); - command->clips.append(parent_clip); - command->fx.append(get_index_in_clip()); - olive::UndoStack.push(command); - update_ui(true); + EffectDeleteCommand* command = new EffectDeleteCommand(); + command->clips.append(parent_clip); + command->fx.append(get_index_in_clip()); + olive::UndoStack.push(command); + update_ui(true); } void Effect::move_up() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from - 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from - 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::move_down() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from + 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from + 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::save_to_file() { - // save effect settings to file + // save effect settings to file QString file = QFileDialog::getSaveFileName(olive::MainWindow, - tr("Save Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Save Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { + // if the user picked a file + if (!file.isEmpty()) { // ensure file ends with .xml extension if (!file.endsWith(".xml", Qt::CaseInsensitive)) { file.append(".xml"); } - QFile file_handle(file); - if (file_handle.open(QFile::WriteOnly)) { + QFile file_handle(file); + if (file_handle.open(QFile::WriteOnly)) { - file_handle.write(save_to_string()); + file_handle.write(save_to_string()); - file_handle.close(); - } else { + file_handle.close(); + } else { QMessageBox::critical(olive::MainWindow, - tr("Save Settings Failed"), - tr("Failed to open \"%1\" for writing.").arg(file), - QMessageBox::Ok); - } - } + tr("Save Settings Failed"), + tr("Failed to open \"%1\" for writing.").arg(file), + QMessageBox::Ok); + } + } } void Effect::load_from_file() { - // load effect settings from file + // load effect settings from file QString file = QFileDialog::getOpenFileName(olive::MainWindow, - tr("Load Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Load Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { - QFile file_handle(file); - if (file_handle.open(QFile::ReadOnly)) { + // if the user picked a file + if (!file.isEmpty()) { + QFile file_handle(file); + if (file_handle.open(QFile::ReadOnly)) { olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); - file_handle.close(); + file_handle.close(); - update_ui(false); - } else { + update_ui(false); + } else { QMessageBox::critical(olive::MainWindow, - tr("Load Settings Failed"), - tr("Failed to open \"%1\" for reading.").arg(file), - QMessageBox::Ok); - } - } + tr("Load Settings Failed"), + tr("Failed to open \"%1\" for reading.").arg(file), + QMessageBox::Ok); + } + } +} + +bool Effect::AlwaysUpdate() +{ + return enable_always_update_; +} + +void Effect::SetAlwaysUpdate(bool b) +{ + enable_always_update_ = b; } int Effect::get_index_in_clip() { - if (parent_clip != nullptr) { - for (int i=0;ieffects.size();i++) { + if (parent_clip != nullptr) { + for (int i=0;ieffects.size();i++) { if (parent_clip->effects.at(i).get() == this) { - return i; - } - } - } - return -1; + return i; + } + } + } + return -1; } bool Effect::is_enabled() { - return container->enabled_check->isChecked(); + return container->enabled_check->isChecked(); } void Effect::set_enabled(bool b) { - container->enabled_check->setChecked(b); -} - -QVariant load_data_from_string(int type, const QString& string) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return string.toDouble(); - case EFFECT_FIELD_COLOR: return QColor(string); - case EFFECT_FIELD_BOOL: return (string == "1"); - case EFFECT_FIELD_COMBO: return string.toInt(); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return string; - } - return QVariant(); -} - -QString save_data_to_string(int type, const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); - case EFFECT_FIELD_COLOR: return data.value().name(); - case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); - case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return data.toString(); - } - return QString(); + container->enabled_check->setChecked(b); } void Effect::load(QXmlStreamReader& stream) { - int row_count = 0; + int row_count = 0; - QString tag = stream.name().toString(); + QString tag = stream.name().toString(); - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); - if (stream.name() == "row" && stream.isStartElement()) { - if (row_count < rows.size()) { - EffectRow* row = rows.at(row_count); - int field_count = 0; + while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { + stream.readNext(); + if (stream.name() == "row" && stream.isStartElement()) { + if (row_count < rows.size()) { + EffectRow* row = rows.at(row_count); + int field_count = 0; - while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { + stream.readNext(); - // read field - if (stream.name() == "field" && stream.isStartElement()) { - if (field_count < row->fieldCount()) { - // match field using ID - int field_number = field_count; - for (int k=0;kfieldCount();l++) { - if (row->field(l)->id == attr.value()) { - field_number = l; -// qInfo() << "Found field by ID"; - break; - } - } - break; - } - } + // read field + if (stream.name() == "field" && stream.isStartElement()) { + if (field_count < row->fieldCount()) { + // match field using ID + int field_number = field_count; + for (int k=0;kfieldCount();l++) { + if (row->field(l)->id() == attr.value()) { + field_number = l; + break; + } + } + break; + } + } - EffectField* field = row->field(field_number); + EffectField* field = row->field(field_number); - // get current field value - for (int k=0;kset_current_data(load_data_from_string(field->type, attr.value().toString())); - break; - } - } + // get current field value + /* + for (int k=0;kSetCurrentValue(field->GetValueFromString(attr.value().toString())); + break; + } + } + */ - while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { + stream.readNext(); - // read keyframes - if (stream.name() == "key" && stream.isStartElement()) { - row->setKeyframing(true); + // read keyframes + if (stream.name() == "key" && stream.isStartElement()) { + row->setKeyframing(true); - EffectKeyframe key; - for (int k=0;ktype, attr.value().toString()); - } else if (attr.name() == "frame") { - key.time = attr.value().toLong(); - } else if (attr.name() == "type") { - key.type = attr.value().toInt(); - } else if (attr.name() == "prehx") { - key.pre_handle_x = attr.value().toDouble(); - } else if (attr.name() == "prehy") { - key.pre_handle_y = attr.value().toDouble(); - } else if (attr.name() == "posthx") { - key.post_handle_x = attr.value().toDouble(); - } else if (attr.name() == "posthy") { - key.post_handle_y = attr.value().toDouble(); - } - } - field->keyframes.append(key); - } - } - } else { - qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; - } - field_count++; - } - } + EffectKeyframe key; + for (int k=0;kConvertStringToValue(attr.value().toString()); + } else if (attr.name() == "frame") { + key.time = attr.value().toLong(); + } else if (attr.name() == "type") { + key.type = attr.value().toInt(); + } else if (attr.name() == "prehx") { + key.pre_handle_x = attr.value().toDouble(); + } else if (attr.name() == "prehy") { + key.pre_handle_y = attr.value().toDouble(); + } else if (attr.name() == "posthx") { + key.post_handle_x = attr.value().toDouble(); + } else if (attr.name() == "posthy") { + key.post_handle_y = attr.value().toDouble(); + } + } + field->keyframes.append(key); + } + } + } else { + qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; + } + field_count++; + } + } - } else { - qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; - } - row_count++; - } else if (stream.isStartElement()) { - custom_load(stream); - } - } + } else { + qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; + } + row_count++; + } else if (stream.isStartElement()) { + 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(is_enabled())); + stream.writeAttribute("name", meta->category + "/" + meta->name); + stream.writeAttribute("enabled", QString::number(is_enabled())); - for (int i=0;isavable) { - stream.writeStartElement("row"); // row - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - stream.writeStartElement("field"); // field - stream.writeAttribute("id", field->id); - stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); - for (int k=0;kkeyframes.size();k++) { - const EffectKeyframe& key = field->keyframes.at(k); - stream.writeStartElement("key"); - stream.writeAttribute("value", save_data_to_string(field->type, key.data)); - stream.writeAttribute("frame", QString::number(key.time)); - stream.writeAttribute("type", QString::number(key.type)); - stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); - stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); - stream.writeAttribute("posthx", QString::number(key.post_handle_x)); - stream.writeAttribute("posthy", QString::number(key.post_handle_y)); - stream.writeEndElement(); // key - } - stream.writeEndElement(); // field - } - stream.writeEndElement(); // row - } - } + for (int i=0;isavable) { + stream.writeStartElement("row"); // row + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + stream.writeStartElement("field"); // field + stream.writeAttribute("id", field->id()); + for (int k=0;kkeyframes.size();k++) { + const EffectKeyframe& key = field->keyframes.at(k); + stream.writeStartElement("key"); + stream.writeAttribute("value", field->ConvertValueToString(key.data)); + stream.writeAttribute("frame", QString::number(key.time)); + stream.writeAttribute("type", QString::number(key.type)); + stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); + stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); + stream.writeAttribute("posthx", QString::number(key.post_handle_x)); + stream.writeAttribute("posthy", QString::number(key.post_handle_y)); + stream.writeEndElement(); // key + } + stream.writeEndElement(); // field + } + stream.writeEndElement(); // row + } + } } void Effect::load_from_string(const QByteArray &s) { - // clear existing keyframe data - for (int i=0;isetKeyframing(false); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - field->keyframes.clear(); - } - } + // clear existing keyframe data + for (int i=0;isetKeyframing(false); + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + field->keyframes.clear(); + } + } - // write settings with xml writer - QXmlStreamReader stream(s); + // write settings with xml writer + QXmlStreamReader stream(s); - while (!stream.atEnd()) { - stream.readNext(); + while (!stream.atEnd()) { + stream.readNext(); - // find the effect opening tag - if (stream.name() == "effect" && stream.isStartElement()) { + // find the effect opening tag + if (stream.name() == "effect" && stream.isStartElement()) { - // check the name to see if it matches this effect - const QXmlStreamAttributes& attributes = stream.attributes(); - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; - QList effects_paths = get_effects_paths(); - const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; + QList effects_paths = get_effects_paths(); + const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; + for (int i=0;iaddShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { - qInfo() << "Vertex shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Vertex shader could not be added"; - } - } - if (!fragPath.isEmpty()) { - if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { - qInfo() << "Fragment shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Fragment shader could not be added"; - } - } - if (glsl_compiled) { - if (glslProgram->link()) { - qInfo() << "Shader program linked successfully"; - } else { - qWarning() << "Shader program failed to link"; - } - } - isOpen = true; - } - } else { - isOpen = true; - } + if (isOpen) { + qWarning() << "Tried to open an effect that was already open"; + close(); + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled && (Flags() & ShaderFlag)) { + if (QOpenGLContext::currentContext() == nullptr) { + qWarning() << "No current context to create a shader program for - will retry next repaint"; + } else { + glslProgram = new QOpenGLShaderProgram(); + validate_meta_path(); + bool glsl_compiled = true; + if (!vertPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { + qInfo() << "Vertex shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Vertex shader could not be added"; + } + } + if (!fragPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { + qInfo() << "Fragment shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Fragment shader could not be added"; + } + } + if (glsl_compiled) { + if (glslProgram->link()) { + qInfo() << "Shader program linked successfully"; + } else { + qWarning() << "Shader program failed to link"; + } + } + isOpen = true; + } + } else { + isOpen = true; + } } void Effect::close() { - if (!isOpen) { - qWarning() << "Tried to close an effect that was already closed"; - } - delete_texture(); - if (glslProgram != nullptr) { - delete glslProgram; - glslProgram = nullptr; - } - isOpen = false; + if (!isOpen) { + qWarning() << "Tried to close an effect that was already closed"; + } + delete_texture(); + if (glslProgram != nullptr) { + delete glslProgram; + glslProgram = nullptr; + } + isOpen = false; } bool Effect::is_glsl_linked() { - return glslProgram != nullptr && glslProgram->isLinked(); + return glslProgram != nullptr && glslProgram->isLinked(); } void Effect::startEffect() { - if (!isOpen) { - open(); - qWarning() << "Tried to start a closed effect - opening"; - } - if (olive::CurrentRuntimeConfig.shaders_are_enabled - && enable_shader - && glslProgram->isLinked()) { - bound = glslProgram->bind(); - } + if (!isOpen) { + open(); + qWarning() << "Tried to start a closed effect - opening"; + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled + && (Flags() & Effect::ShaderFlag) + && glslProgram->isLinked()) { + bound = glslProgram->bind(); + } } void Effect::endEffect() { - if (bound) glslProgram->release(); - bound = false; + if (bound) glslProgram->release(); + bound = false; +} + +int Effect::Flags() +{ + return flags_; +} + +void Effect::SetFlags(int flags) +{ + flags_ = flags; } int Effect::getIterations() { - return iterations; + return iterations; } void Effect::setIterations(int i) { - iterations = i; + iterations = i; } void Effect::process_image(double, uint8_t *, uint8_t *, int){} EffectPtr Effect::copy(Clip *c) { EffectPtr copy = Effect::Create(c, meta); - copy->set_enabled(is_enabled()); - copy_field_keyframes(copy); - return copy; + copy->set_enabled(is_enabled()); + copy_field_keyframes(copy); + return copy; } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { glslProgram->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); - glslProgram->setUniformValue("time", GLfloat(timecode)); - glslProgram->setUniformValue("iteration", iteration); + glslProgram->setUniformValue("time", GLfloat(timecode)); + glslProgram->setUniformValue("iteration", iteration); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - glslProgram->setUniformValue(field->id.toUtf8().constData(), GLfloat(field->get_double_value(timecode))); - break; - case EFFECT_FIELD_COLOR: - glslProgram->setUniformValue( - field->id.toUtf8().constData(), - GLfloat(field->get_color_value(timecode).redF()), - GLfloat(field->get_color_value(timecode).greenF()), - GLfloat(field->get_color_value(timecode).blueF()) - ); - break; - case EFFECT_FIELD_STRING: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_BOOL: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_FILE: break; // can you even send a string to a uniform value? - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id().isEmpty()) { + switch (field->type()) { + case EffectField::EFFECT_FIELD_DOUBLE: + { + DoubleField* double_field = static_cast(field); + glslProgram->setUniformValue(double_field->id().toUtf8().constData(), + GLfloat(double_field->GetDoubleAt(timecode))); + } + break; + case EffectField::EFFECT_FIELD_COLOR: + { + ColorField* color_field = static_cast(field); + glslProgram->setUniformValue( + color_field->id().toUtf8().constData(), + GLfloat(color_field->GetColorAt(timecode).redF()), + GLfloat(color_field->GetColorAt(timecode).greenF()), + GLfloat(color_field->GetColorAt(timecode).blueF()) + ); + } + break; + case EffectField::EFFECT_FIELD_BOOL: + glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); + break; + case EffectField::EFFECT_FIELD_COMBO: + glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); + break; + + // can you even send a string to a uniform value? + case EffectField::EFFECT_FIELD_STRING: + case EffectField::EFFECT_FIELD_FONT: + case EffectField::EFFECT_FIELD_FILE: + break; + } + } + } + } } void Effect::process_coords(double, GLTextureCoords&, int) {} GLuint Effect::process_superimpose(double timecode) { - bool dimensions_changed = false; - bool redrew_image = false; + bool dimensions_changed = false; + bool redrew_image = false; int width = parent_clip->media_width(); int height = parent_clip->media_height(); - if (width != img.width() || height != img.height()) { - img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); - dimensions_changed = true; - } + if (width != img.width() || height != img.height()) { + img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); + dimensions_changed = true; + } - if (valueHasChanged(timecode) || dimensions_changed || enable_always_update) { - redraw(timecode); - redrew_image = true; - } + if (valueHasChanged(timecode) || dimensions_changed || AlwaysUpdate()) { + redraw(timecode); + redrew_image = true; + } - if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { - delete_texture(); + if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { + delete_texture(); - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); - texture->setSize(img.width(), img.height()); - texture->setFormat(QOpenGLTexture::RGBA8_UNorm); - texture->setMipLevels(texture->maximumMipLevels()); - texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + texture->setSize(img.width(), img.height()); + texture->setFormat(QOpenGLTexture::RGBA8_UNorm); + texture->setMipLevels(texture->maximumMipLevels()); + texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); - redrew_image = true; - } + redrew_image = true; + } - if (redrew_image) { - texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); - } + if (redrew_image) { + texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); + } - return texture->textureId(); + return texture->textureId(); } void Effect::process_audio(double, double, quint8*, int, int) {} @@ -942,158 +968,161 @@ void Effect::process_audio(double, double, quint8*, int, int) {} void Effect::gizmo_draw(double, GLTextureCoords &) {} void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) { - for (int i=0;ix_field1 != nullptr) { - gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1); - gizmo->x_field1->make_key_from_change(ca); - } - if (gizmo->y_field1 != nullptr) { - gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1); - gizmo->y_field1->make_key_from_change(ca); - } - if (gizmo->x_field2 != nullptr) { - gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2); - gizmo->x_field2->make_key_from_change(ca); - } - if (gizmo->y_field2 != nullptr) { - gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2); - gizmo->y_field2->make_key_from_change(ca); - } - if (done) olive::UndoStack.push(ca); - break; - } - } + for (int i=0;ix_field1 != nullptr) { + gizmo->x_field1->SetValueAt(timecode, gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1); + //gizmo->x_field1->make_key_from_change(ca); + } + if (gizmo->y_field1 != nullptr) { + gizmo->y_field1->SetValueAt(timecode, gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1); + //gizmo->y_field1->make_key_from_change(ca); + } + if (gizmo->x_field2 != nullptr) { + gizmo->x_field2->SetValueAt(timecode, gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2); + //gizmo->x_field2->make_key_from_change(ca); + } + if (gizmo->y_field2 != nullptr) { + gizmo->y_field2->SetValueAt(timecode, gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2); + //gizmo->y_field2->make_key_from_change(ca); + } + if (done) olive::UndoStack.push(ca); + break; + } + } } void Effect::gizmo_world_to_screen() { - GLfloat view_val[16]; - GLfloat projection_val[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, view_val); - glGetFloatv(GL_PROJECTION_MATRIX, projection_val); + GLfloat view_val[16]; + GLfloat projection_val[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, view_val); + glGetFloatv(GL_PROJECTION_MATRIX, projection_val); - QMatrix4x4 view_matrix(view_val); - QMatrix4x4 projection_matrix(projection_val); + QMatrix4x4 view_matrix(view_val); + QMatrix4x4 projection_matrix(projection_val); - for (int i=0;iget_point_count();j++) { - QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); + for (int j=0;jget_point_count();j++) { + QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); - int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); - int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); + int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); + int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); - g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); - } - } + g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); + } + } } bool Effect::are_gizmos_enabled() { - return (gizmos.size() > 0); + return (gizmos.size() > 0); } void Effect::redraw(double) { - /* - // run javascript - QPainter p(&img); - painter_wrapper.img = &img; - painter_wrapper.painter = &p; + /* + // run javascript + QPainter p(&img); + painter_wrapper.img = &img; + painter_wrapper.painter = &p; - jsEngine.globalObject().setProperty("painter", wrapper_obj); + jsEngine.globalObject().setProperty("painter", wrapper_obj); jsEngine.globalObject().setProperty("width", parent_clip->media_width()); jsEngine.globalObject().setProperty("height", parent_clip->media_height()); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); - break; - case EFFECT_FIELD_COLOR: - jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); - break; - case EFFECT_FIELD_STRING: - jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); - break; - case EFFECT_FIELD_BOOL: - jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: - jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); - break; - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); + break; + case EFFECT_FIELD_COLOR: + jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); + break; + case EFFECT_FIELD_STRING: + jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); + break; + case EFFECT_FIELD_BOOL: + jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: + jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); + break; + } + } + } + } - jsEngine.evaluate(script); - */ + jsEngine.evaluate(script); + */ } bool Effect::valueHasChanged(double timecode) { - if (cachedValues.size() == 0) { - for (int i=0;ifieldCount();j++) { - cachedValues.append(crow->field(j)->get_current_data()); - } - } - return true; - } else { - bool changed = false; - int index = 0; - for (int i=0;ifieldCount();j++) { - EffectField* field = crow->field(j); - field->validate_keyframe_data(timecode); - if (cachedValues.at(index) != field->get_current_data()) { - changed = true; - } - cachedValues[index] = field->get_current_data(); - index++; - } - } - return changed; - } + if (cachedValues.size() == 0) { + + for (int i=0;ifieldCount();j++) { + cachedValues.append(crow->field(j)->GetValueAt(timecode)); + } + } + return true; + + } else { + + bool changed = false; + int index = 0; + for (int i=0;ifieldCount();j++) { + EffectField* field = crow->field(j); + if (cachedValues.at(index) != field->GetValueAt(timecode)) { + changed = true; + } + cachedValues[index] = field->GetValueAt(timecode); + index++; + } + } + return changed; + + } } void Effect::delete_texture() { - if (texture != nullptr) { - delete texture; - texture = nullptr; - } + if (texture != nullptr) { + delete texture; + texture = nullptr; + } } const EffectMeta* get_meta_from_name(const QString& input) { - int split_index = input.indexOf('/'); - QString category; - if (split_index > -1) { - category = input.left(split_index); - } - QString name = input.mid(split_index + 1); + int split_index = input.indexOf('/'); + QString category; + if (split_index > -1) { + category = input.left(split_index); + } + QString name = input.mid(split_index + 1); - for (int j=0;j(a) + static_cast(b); - mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); - return static_cast(mixed_sample); + qint32 mixed_sample = static_cast(a) + static_cast(b); + mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + return static_cast(mixed_sample); } diff --git a/project/effect.h b/project/effect.h index 64224ec97..dea03233c 100644 --- a/project/effect.h +++ b/project/effect.h @@ -42,6 +42,9 @@ #include "ui/collapsiblewidget.h" #include "ui/checkboxex.h" +#include "effectfields.h" +#include "effectrow.h" +#include "effectgizmo.h" class Clip; @@ -94,36 +97,6 @@ enum EffectInternal { EFFECT_INTERNAL_COUNT }; -enum EffectBlendMode { - BLEND_MODE_ADD, - BLEND_MODE_AVERAGE, - BLEND_MODE_COLORBURN, - BLEND_MODE_COLORDODGE, - BLEND_MODE_DARKEN, - BLEND_MODE_DIFFERENCE, - BLEND_MODE_EXCLUSION, - BLEND_MODE_GLOW, - BLEND_MODE_HARDLIGHT, - BLEND_MODE_HARDMIX, - BLEND_MODE_LIGHTEN, - BLEND_MODE_LINEARBURN, - BLEND_MODE_LINEARDODGE, - BLEND_MODE_LINEARLIGHT, - BLEND_MODE_MULTIPLY, - BLEND_MODE_NEGATION, - BLEND_MODE_NORMAL, - BLEND_MODE_OVERLAY, - BLEND_MODE_PHOENIX, - BLEND_MODE_PINLIGHT, - BLEND_MODE_REFLECT, - BLEND_MODE_SCREEN, - BLEND_MODE_SOFTLIGHT, - BLEND_MODE_SUBSTRACT, - BLEND_MODE_SUBTRACT, - BLEND_MODE_VIVIDLIGHT, - BLEND_MODE_COUNT -}; - struct GLTextureCoords { int grid_size; @@ -161,10 +134,6 @@ const EffectMeta* get_meta_from_name(const QString& input); qint16 mix_audio_sample(qint16 a, qint16 b); -#include "effectfield.h" -#include "effectrow.h" -#include "effectgizmo.h" - class Effect : public QObject { Q_OBJECT public: @@ -207,10 +176,14 @@ public: virtual void startEffect(); virtual void endEffect(); - bool enable_shader; - bool enable_coords; - bool enable_superimpose; - bool enable_image; + enum VideoEffectFlags { + ShaderFlag = 0x1, + CoordsFlag = 0x2, + SuperimposeFlag = 0x4, + ImageFlag = 0x8 + }; + int Flags(); + void SetFlags(int flags); int getIterations(); void setIterations(int i); @@ -258,8 +231,9 @@ protected: QImage img; QOpenGLTexture* texture; - // enable effect to update constantly - bool enable_always_update; + bool AlwaysUpdate(); + void SetAlwaysUpdate(bool b); + private: // superimpose effect QString script; @@ -272,6 +246,11 @@ private: bool bound; int iterations; + int flags_; + + // enable effect to update constantly + bool enable_always_update_; + // superimpose functions virtual void redraw(double timecode); bool valueHasChanged(double timecode); diff --git a/project/effectfield.cpp b/project/effectfield.cpp deleted file mode 100644 index 5758bd4c8..000000000 --- a/project/effectfield.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "effectfield.h" - -#include "ui/labelslider.h" -#include "ui/colorbutton.h" -#include "ui/texteditex.h" -#include "ui/checkboxex.h" -#include "ui/comboboxex.h" -#include "ui/fontcombobox.h" -#include "ui/embeddedfilechooser.h" - -#include "io/config.h" - -#include "effectrow.h" -#include "effect.h" - -#include "project/undo.h" -#include "project/clip.h" -#include "project/sequence.h" - -#include "io/math.h" - -#include -#include - -#include "debug.h" - -EffectField::EffectField(EffectRow *parent, int t, const QString &i) : - parent_row(parent), - type(t), - id(i) -{ - switch (t) { - case EFFECT_FIELD_DOUBLE: - { - LabelSlider* ls = new LabelSlider(); - ui_element = ls; - connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change())); - connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked())); - } - break; - case EFFECT_FIELD_COLOR: - { - ColorButton* cb = new ColorButton(); - ui_element = cb; - connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_STRING: - { - TextEditEx* edit = new TextEditEx(); - - // TODO magic number 2 - i'm not sure how to make this work otherwise though - edit->setFixedHeight(qCeil(edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + edit->document()->documentMargin() + edit->document()->documentMargin() + 2)); - - edit->setUndoRedoEnabled(true); - ui_element = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_BOOL: - { - CheckboxEx* cb = new CheckboxEx(); - ui_element = cb; - connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change())); - connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); - } - break; - case EFFECT_FIELD_COMBO: - { - ComboBoxEx* cb = new ComboBoxEx(); - ui_element = cb; - connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FONT: - { - FontCombobox* fcb = new FontCombobox(); - ui_element = fcb; - connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FILE: - { - EmbeddedFileChooser* efc = new EmbeddedFileChooser(); - ui_element = efc; - connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change())); - } - break; - } -} - -EffectField::~EffectField() {} - -double EffectField::get_validated_keyframe_handle(int key, bool post) { - int comp_key = -1; - - // find keyframe before or after this one - for (int i=0;i keyframes.at(key).time) == post) - && (comp_key == -1 - || ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) { - // compare with next keyframe for post or previous frame for pre - comp_key = i; - } - } - - double adjusted_key = post ? keyframes.at(key).post_handle_x : keyframes.at(key).pre_handle_x; - - // if this is the earliest/latest keyframe, no validation is required - if (comp_key == -1) { - return adjusted_key; - } - - double comp = keyframes.at(comp_key).time - keyframes.at(key).time; - - // if comp keyframe is bezier, validate with its accompanying handle - if (keyframes.at(comp_key).type == EFFECT_KEYFRAME_BEZIER) { - double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle_x : keyframes.at(comp_key).post_handle_x); - // return an average - if ((post && keyframes.at(key).post_handle_x > relative_comp_handle) - || (!post && keyframes.at(key).pre_handle_x < relative_comp_handle)) { - adjusted_key = (adjusted_key + relative_comp_handle)*0.5; - } - } - - // don't let handle go beyond the compare keyframe's time - if (post == (adjusted_key > comp)) { - return comp; - } - - if (post == (adjusted_key < 0)) { - return 0; - } - - // original value is valid - return adjusted_key; -} - -QVariant EffectField::get_previous_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_BOOL: return !static_cast(ui_element)->isChecked(); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->getPreviousIndex(); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->getPreviousValue(); - } - return QVariant(); -} - -QVariant EffectField::get_current_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->value(); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->get_color(); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPlainTextEx(); - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->isChecked(); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->currentIndex(); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->currentText(); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->getFilename(); - } - return QVariant(); -} - -double EffectField::frameToTimecode(long frame) { - return (double(frame) / parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -long EffectField::timecodeToFrame(double timecode) { - return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -void EffectField::set_current_data(const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->set_value(data.toDouble(), false); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->set_color(data.value()); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->setPlainTextEx(data.toString()); - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->setChecked(data.toBool()); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->setCurrentIndexEx(data.toInt()); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->setCurrentTextEx(data.toString()); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->setFilename(data.toString()); - } -} - -void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { - int before_keyframe_index = -1; - int after_keyframe_index = -1; - long before_keyframe_time = LONG_MIN; - long after_keyframe_time = LONG_MAX; - long frame = timecodeToFrame(timecode); - - for (int i=0;i before_keyframe_time) { - before_keyframe_index = i; - before_keyframe_time = eval_keyframe_time; - } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { - after_keyframe_index = i; - after_keyframe_time = eval_keyframe_time; - } - } - - if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { - // interpolate - before = before_keyframe_index; - after = after_keyframe_index; - progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); - } else if (before_keyframe_index > -1) { - before = before_keyframe_index; - after = before_keyframe_index; - } else { - before = after_keyframe_index; - after = after_keyframe_index; - } -} - -bool EffectField::hasKeyframes() { - return (parent_row->isKeyframing() && keyframes.size() > 0); -} - -QVariant EffectField::validate_keyframe_data(double timecode, bool async) { - if (hasKeyframes()) { - int before_keyframe; - int after_keyframe; - double progress; - get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); - - const QVariant& before_data = keyframes.at(before_keyframe).data; - switch (type) { - case EFFECT_FIELD_DOUBLE: - { - double value; - if (before_keyframe == after_keyframe) { - value = keyframes.at(before_keyframe).data.toDouble(); - } else { - const EffectKeyframe& before_key = keyframes.at(before_keyframe); - const EffectKeyframe& after_key = keyframes.at(after_keyframe); - - double before_dbl = before_key.data.toDouble(); - double after_dbl = after_key.data.toDouble(); - - if (before_key.type == EFFECT_KEYFRAME_HOLD) { - // hold - value = before_dbl; - } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { - // bezier interpolation - if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { - // cubic bezier - double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+get_validated_keyframe_handle(before_keyframe, true), after_key.time+get_validated_keyframe_handle(after_keyframe, false), after_key.time); - value = cubic_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl+after_key.pre_handle_y, after_dbl, t); - } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier - // last keyframe is the bezier one - double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+get_validated_keyframe_handle(before_keyframe, true), after_key.time); - value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); - } else { - // this keyframe is the bezier one - double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+get_validated_keyframe_handle(after_keyframe, false), after_key.time); - value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); - } - } else { - // linear - value = double_lerp(before_dbl, after_dbl, progress); - } - } - if (async) { - return value; - } - static_cast(ui_element)->set_value(value, false); - } - break; - case EFFECT_FIELD_COLOR: - { - QColor value; - if (before_keyframe == after_keyframe) { - value = keyframes.at(before_keyframe).data.value(); - } else { - QColor before_data = keyframes.at(before_keyframe).data.value(); - QColor after_data = keyframes.at(after_keyframe).data.value(); - value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); - } - if (async) { - return value; - } - static_cast(ui_element)->set_color(value); - } - break; - case EFFECT_FIELD_STRING: - if (async) { - return before_data; - } - static_cast(ui_element)->setPlainTextEx(before_data.toString()); - break; - case EFFECT_FIELD_BOOL: - if (async) { - return before_data; - } - static_cast(ui_element)->setChecked(before_data.toBool()); - break; - case EFFECT_FIELD_COMBO: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentIndexEx(before_data.toInt()); - break; - case EFFECT_FIELD_FONT: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentTextEx(before_data.toString()); - break; - case EFFECT_FIELD_FILE: - if (async) { - return before_data; - } - static_cast(ui_element)->setFilename(before_data.toString()); - break; - } - } - return QVariant(); -} - -void EffectField::ui_element_change() { - bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); - ComboAction* ca = nullptr; - if (!dragging_double) ca = new ComboAction(); - make_key_from_change(ca); - if (!dragging_double) olive::UndoStack.push(ca); - emit changed(); -} - -void EffectField::make_key_from_change(ComboAction* ca) { - if (parent_row->isKeyframing()) { - parent_row->set_keyframe_now(ca); - } else if (ca != nullptr) { - // set undo - ca->append(new EffectFieldUndo(this)); - } -} - -QWidget* EffectField::get_ui_element() { - return ui_element; -} - -bool EffectField::is_enabled() { - return ui_element->isEnabled(); -} - -void EffectField::set_enabled(bool e) { - ui_element->setEnabled(e); -} - -double EffectField::get_double_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toDouble(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->value(); -} - -void EffectField::set_double_value(double v) { - static_cast(ui_element)->set_value(v, false); -} - -void EffectField::set_double_default_value(double v) { - static_cast(ui_element)->set_default_value(v); -} - -void EffectField::set_double_minimum_value(double v) { - static_cast(ui_element)->set_minimum_value(v); -} - -void EffectField::set_double_maximum_value(double v) { - static_cast(ui_element)->set_maximum_value(v); -} - -void EffectField::add_combo_item(const QString& name, const QVariant& data) { - static_cast(ui_element)->addItem(name, data); -} - -int EffectField::get_combo_index(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toInt(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentIndex(); -} - -QVariant EffectField::get_combo_data(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentData(); -} - -QString EffectField::get_combo_string(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_combo_index(int index) { - static_cast(ui_element)->setCurrentIndexEx(index); -} - -void EffectField::set_combo_string(const QString& s) { - static_cast(ui_element)->setCurrentTextEx(s); -} - -bool EffectField::get_bool_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toBool(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->isChecked(); -} - -void EffectField::set_bool_value(bool b) { - return static_cast(ui_element)->setChecked(b); -} - -QString EffectField::get_string_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->getPlainTextEx(); -} - -void EffectField::set_string_value(const QString& s) { - static_cast(ui_element)->setPlainTextEx(s); -} - -QString EffectField::get_font_name(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_font_name(const QString& s) { - static_cast(ui_element)->setCurrentText(s); -} - -QColor EffectField::get_color_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).value(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->get_color(); -} - -void EffectField::set_color_value(QColor color) { - static_cast(ui_element)->set_color(color); -} - -QString EffectField::get_filename(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->getFilename(); -} - -void EffectField::set_filename(const QString &s) { - static_cast(ui_element)->setFilename(s); -} diff --git a/project/effectfield.h b/project/effectfield.h deleted file mode 100644 index 4818d5538..000000000 --- a/project/effectfield.h +++ /dev/null @@ -1,108 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef EFFECTFIELD_H -#define EFFECTFIELD_H - -enum EffectFieldType { - EFFECT_FIELD_DOUBLE, - EFFECT_FIELD_COLOR, - EFFECT_FIELD_STRING, - EFFECT_FIELD_BOOL, - EFFECT_FIELD_COMBO, - EFFECT_FIELD_FONT, - EFFECT_FIELD_FILE -}; - -#include -#include -#include - -#include "keyframe.h" - -class EffectRow; -class ComboAction; - -class EffectField : public QObject { - Q_OBJECT -public: - EffectField(EffectRow* parent, int t, const QString& i); - ~EffectField(); - - EffectRow* parent_row; - int type; - QString id; - - double get_validated_keyframe_handle(int key, bool post); - - QVariant get_previous_data(); - QVariant get_current_data(); - double frameToTimecode(long frame); - long timecodeToFrame(double timecode); - void set_current_data(const QVariant&); - void get_keyframe_data(double timecode, int& before, int& after, double& d); - QVariant validate_keyframe_data(double timecode, bool async = false); - - double get_double_value(double timecode, bool async = false); - void set_double_value(double v); - void set_double_default_value(double v); - void set_double_minimum_value(double v); - void set_double_maximum_value(double v); - - QString get_string_value(double timecode, bool async = false); - void set_string_value(const QString &s); - - void add_combo_item(const QString& name, const QVariant &data); - int get_combo_index(double timecode, bool async = false); - QVariant get_combo_data(double timecode); - QString get_combo_string(double timecode); - void set_combo_index(int index); - void set_combo_string(const QString& s); - - bool get_bool_value(double timecode, bool async = false); - void set_bool_value(bool b); - - QString get_font_name(double timecode, bool async = false); - void set_font_name(const QString& s); - - QColor get_color_value(double timecode, bool async = false); - void set_color_value(QColor color); - - QString get_filename(double timecode, bool async = false); - void set_filename(const QString& s); - - QWidget* get_ui_element(); - bool is_enabled(); - void set_enabled(bool e); - QVector keyframes; - QWidget* ui_element; - - void make_key_from_change(ComboAction* ca); -public slots: - void ui_element_change(); -private: - bool hasKeyframes(); -signals: - void changed(); - void toggled(bool); - void clicked(); -}; - -#endif // EFFECTFIELD_H diff --git a/project/effectfields.h b/project/effectfields.h new file mode 100644 index 000000000..668108ae6 --- /dev/null +++ b/project/effectfields.h @@ -0,0 +1,12 @@ +#ifndef EFFECTFIELDS_H +#define EFFECTFIELDS_H + +#include "effectfields/boolfield.h" +#include "effectfields/colorfield.h" +#include "effectfields/combofield.h" +#include "effectfields/doublefield.h" +#include "effectfields/filefield.h" +#include "effectfields/fontfield.h" +#include "effectfields/stringfield.h" + +#endif // EFFECTFIELDS_H diff --git a/project/effectfields/boolfield.cpp b/project/effectfields/boolfield.cpp new file mode 100644 index 000000000..e230c7ad7 --- /dev/null +++ b/project/effectfields/boolfield.cpp @@ -0,0 +1,20 @@ +#include "boolfield.h" + +BoolField::BoolField(EffectRow *parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_BOOL) +{} + +bool BoolField::GetBoolAt(double timecode) +{ + return GetValueAt(timecode).toBool(); +} + +QVariant BoolField::ConvertStringToValue(const QString &s) +{ + return (s == "1"); +} + +QString BoolField::ConvertValueToString(const QVariant &v) +{ + return QString::number(v.toBool()); +} diff --git a/project/effectfields/boolfield.h b/project/effectfields/boolfield.h new file mode 100644 index 000000000..ee3fd848c --- /dev/null +++ b/project/effectfields/boolfield.h @@ -0,0 +1,18 @@ +#ifndef BOOLFIELD_H +#define BOOLFIELD_H + +#include "effectfield.h" + +class BoolField : public EffectField +{ + Q_OBJECT +public: + BoolField(EffectRow* parent, const QString& id); + + bool GetBoolAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // BOOLFIELD_H diff --git a/project/effectfields/colorfield.cpp b/project/effectfields/colorfield.cpp new file mode 100644 index 000000000..435c79ddc --- /dev/null +++ b/project/effectfields/colorfield.cpp @@ -0,0 +1,22 @@ +#include "colorfield.h" + +#include + +ColorField::ColorField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_COLOR) +{} + +QColor ColorField::GetColorAt(double timecode) +{ + return GetValueAt(timecode).value(); +} + +QVariant ColorField::ConvertStringToValue(const QString &s) +{ + return QColor(s); +} + +QString ColorField::ConvertValueToString(const QVariant &v) +{ + return v.value().name(); +} diff --git a/project/effectfields/colorfield.h b/project/effectfields/colorfield.h new file mode 100644 index 000000000..91b4b8a7a --- /dev/null +++ b/project/effectfields/colorfield.h @@ -0,0 +1,18 @@ +#ifndef COLORFIELD_H +#define COLORFIELD_H + +#include "effectfield.h" + +class ColorField : public EffectField +{ + Q_OBJECT +public: + ColorField(EffectRow* parent, const QString& id); + + QColor GetColorAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // COLORFIELD_H diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp new file mode 100644 index 000000000..342dd6a21 --- /dev/null +++ b/project/effectfields/combofield.cpp @@ -0,0 +1,25 @@ +#include "combofield.h" + +ComboField::ComboField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_COMBO) +{} + +void ComboField::AddItem(const QString &text, const QVariant &data) +{ + ComboFieldItem item; + + item.name = text; + item.data.append(data); + + items_.append(item); +} + +QVariant ComboField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString ComboField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/combofield.h b/project/effectfields/combofield.h new file mode 100644 index 000000000..00c229259 --- /dev/null +++ b/project/effectfields/combofield.h @@ -0,0 +1,29 @@ +#ifndef COMBOFIELD_H +#define COMBOFIELD_H + +#include "effectfield.h" + +struct ComboFieldItem { + QString name; + QVector data; +}; + +class ComboField : public EffectField +{ + Q_OBJECT +public: + ComboField(EffectRow* parent, const QString& id); + + void AddItem(const QString& text, const QVariant& data); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); + +signals: + void IndexChanged(int i); + +private: + QVector items_; +}; + +#endif // COMBOFIELD_H diff --git a/project/effectfields/doublefield.cpp b/project/effectfields/doublefield.cpp new file mode 100644 index 000000000..783f65ed0 --- /dev/null +++ b/project/effectfields/doublefield.cpp @@ -0,0 +1,60 @@ +#include "doublefield.h" + +DoubleField::DoubleField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_DOUBLE), + min_(DBL_MIN), + max_(DBL_MAX), + value_set_(false) +{ + connect(this, SIGNAL(Changed()), this, SLOT(ValueHasBeenSet()), Qt::DirectConnection); +} + +double DoubleField::GetDoubleAt(double timecode) +{ + return GetValueAt(timecode).toDouble(); +} + +void DoubleField::SetMinimum(double minimum) +{ + min_ = minimum; +} + +void DoubleField::SetMaximum(double maximum) +{ + max_ = maximum; +} + +void DoubleField::SetDefault(double d) +{ + default_ = d; + + if (!value_set_) { + SetValueAt(0, d); + value_set_ = false; + } +} + +void DoubleField::SetDisplayType(LabelSlider::DisplayType type) +{ + display_type_ = type; +} + +void DoubleField::SetFrameRate(const double &rate) +{ + frame_rate_ = rate; +} + +QVariant DoubleField::ConvertStringToValue(const QString &s) +{ + return s.toDouble(); +} + +QString DoubleField::ConvertValueToString(const QVariant &v) +{ + return QString::number(v.toDouble()); +} + +void DoubleField::ValueHasBeenSet() +{ + value_set_ = true; +} diff --git a/project/effectfields/doublefield.h b/project/effectfields/doublefield.h new file mode 100644 index 000000000..c5deb0c21 --- /dev/null +++ b/project/effectfields/doublefield.h @@ -0,0 +1,50 @@ +#ifndef DOUBLEFIELD_H +#define DOUBLEFIELD_H + +#include "effectfield.h" +#include "ui/labelslider.h" + +class DoubleField : public EffectField +{ + Q_OBJECT +public: + DoubleField(EffectRow* parent, const QString& id); + + /** + * @brief Get double value at timecode + * + * Convenience function. Equivalent to GetValueAt().toDouble() + * + * @param timecode + * + * Timecode to retrieve value at + * + * @return + * + * Double value at the set timecode + */ + double GetDoubleAt(double timecode); + + void SetMinimum(double minimum); + void SetMaximum(double maximum); + void SetDefault(double maximum); + + void SetDisplayType(LabelSlider::DisplayType type); + void SetFrameRate(const double& rate); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +private: + double min_; + double max_; + double default_; + + LabelSlider::DisplayType display_type_; + double frame_rate_; + + bool value_set_; +private slots: + void ValueHasBeenSet(); +}; + +#endif // DOUBLEFIELD_H diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp new file mode 100644 index 000000000..96d32366b --- /dev/null +++ b/project/effectfields/effectfield.cpp @@ -0,0 +1,368 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "effectfield.h" + +#include "ui/labelslider.h" +#include "ui/colorbutton.h" +#include "ui/texteditex.h" +#include "ui/checkboxex.h" +#include "ui/comboboxex.h" +#include "ui/fontcombobox.h" +#include "ui/embeddedfilechooser.h" + +#include "io/config.h" + +#include "project/effectrow.h" +#include "project/effect.h" + +#include "project/undo.h" +#include "project/clip.h" +#include "project/sequence.h" + +#include "io/math.h" + +#include +#include + +#include "debug.h" + +EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) : + QObject(parent), + type_(t), + id_(i), + enabled_(true) +{ + // EffectField MUST be created with a parent. + Q_ASSERT(parent != nullptr); + Q_ASSERT(!i.isEmpty()); + + parent->AddField(this); + /* + switch (t) { + case EFFECT_FIELD_DOUBLE: + { + LabelSlider* ls = new LabelSlider(); + ui_element = ls; + connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change())); + connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked())); + } + break; + case EFFECT_FIELD_COLOR: + { + ColorButton* cb = new ColorButton(); + ui_element = cb; + connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_STRING: + { + TextEditEx* edit = new TextEditEx(); + + // TODO magic number 2 - It seems to just be +1 for the top and +1 for the bottom, which is sort of sensible but + // feels a little tacky? + edit->setFixedHeight(qCeil(edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + + edit->document()->documentMargin() + + edit->document()->documentMargin() + + 2)); + + edit->setUndoRedoEnabled(true); + ui_element = edit; + connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_BOOL: + { + CheckboxEx* cb = new CheckboxEx(); + ui_element = cb; + connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change())); + connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + } + break; + case EFFECT_FIELD_COMBO: + { + ComboBoxEx* cb = new ComboBoxEx(); + ui_element = cb; + connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_FONT: + { + FontCombobox* fcb = new FontCombobox(); + ui_element = fcb; + connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_FILE: + { + EmbeddedFileChooser* efc = new EmbeddedFileChooser(); + ui_element = efc; + connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change())); + } + break; + } + */ + + // Set a very base default value + SetValueAt(0, 0); +} + +EffectField::~EffectField() {} + +EffectRow *EffectField::GetParentRow() +{ + return static_cast(parent()); +} + +int EffectField::GetColumnSpan() +{ + return colspan_; +} + +void EffectField::SetColumnSpan(int i) +{ + colspan_ = i; +} + +QVariant EffectField::GetValueAt(double timecode) +{ + Q_ASSERT(!keyframes.isEmpty()); + + if (HasKeyframes()) { + int before_keyframe; + int after_keyframe; + double progress; + get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); + + const QVariant& before_data = keyframes.at(before_keyframe).data; + switch (type_) { + case EFFECT_FIELD_DOUBLE: + { + double value; + if (before_keyframe == after_keyframe) { + value = keyframes.at(before_keyframe).data.toDouble(); + } else { + const EffectKeyframe& before_key = keyframes.at(before_keyframe); + const EffectKeyframe& after_key = keyframes.at(after_keyframe); + + double before_dbl = before_key.data.toDouble(); + double after_dbl = after_key.data.toDouble(); + + if (before_key.type == EFFECT_KEYFRAME_HOLD) { + // hold + value = before_dbl; + } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { + // bezier interpolation + if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { + // cubic bezier + double t = cubic_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); + value = cubic_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl+after_key.pre_handle_y, after_dbl, t); + } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier + // last keyframe is the bezier one + double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); + value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); + } else { + // this keyframe is the bezier one + double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); + value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); + } + } else { + // linear + value = double_lerp(before_dbl, after_dbl, progress); + } + } + return value; + } + case EFFECT_FIELD_COLOR: + { + QColor value; + if (before_keyframe == after_keyframe) { + value = keyframes.at(before_keyframe).data.value(); + } else { + QColor before_data = keyframes.at(before_keyframe).data.value(); + QColor after_data = keyframes.at(after_keyframe).data.value(); + value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); + } + return value; + } + case EFFECT_FIELD_STRING: + case EFFECT_FIELD_BOOL: + case EFFECT_FIELD_COMBO: + case EFFECT_FIELD_FONT: + case EFFECT_FIELD_FILE: + return before_data; + } + } + + return keyframes.first().data; +} + +void EffectField::SetValueAt(double timecode, const QVariant &value) +{ + if (keyframes.isEmpty()) { + EffectKeyframe key; + key.data = value; + keyframes.append(key); + return; + } + + if (GetParentRow()->isKeyframing()) { + // create keyframe here + } else { + keyframes.first().data = value; + } + + emit Changed(); +} + +const EffectField::EffectFieldType &EffectField::type() +{ + return type_; +} + +const QString &EffectField::id() +{ + return id_; +} + +double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { + int comp_key = -1; + + // find keyframe before or after this one + for (int i=0;i keyframes.at(key).time) == post) + && (comp_key == -1 + || ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) { + // compare with next keyframe for post or previous frame for pre + comp_key = i; + } + } + + double adjusted_key = post ? keyframes.at(key).post_handle_x : keyframes.at(key).pre_handle_x; + + // if this is the earliest/latest keyframe, no validation is required + if (comp_key == -1) { + return adjusted_key; + } + + double comp = keyframes.at(comp_key).time - keyframes.at(key).time; + + // if comp keyframe is bezier, validate with its accompanying handle + if (keyframes.at(comp_key).type == EFFECT_KEYFRAME_BEZIER) { + double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle_x : keyframes.at(comp_key).post_handle_x); + // return an average + if ((post && keyframes.at(key).post_handle_x > relative_comp_handle) + || (!post && keyframes.at(key).pre_handle_x < relative_comp_handle)) { + adjusted_key = (adjusted_key + relative_comp_handle)*0.5; + } + } + + // don't let handle go beyond the compare keyframe's time + if (post == (adjusted_key > comp)) { + return comp; + } + + if (post == (adjusted_key < 0)) { + return 0; + } + + // original value is valid + return adjusted_key; +} + +double EffectField::frameToTimecode(long frame) { + return (double(frame) / GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); +} + +long EffectField::timecodeToFrame(double timecode) { + return qRound(timecode * GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); +} + +void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { + int before_keyframe_index = -1; + int after_keyframe_index = -1; + long before_keyframe_time = LONG_MIN; + long after_keyframe_time = LONG_MAX; + long frame = timecodeToFrame(timecode); + + for (int i=0;i before_keyframe_time) { + before_keyframe_index = i; + before_keyframe_time = eval_keyframe_time; + } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { + after_keyframe_index = i; + after_keyframe_time = eval_keyframe_time; + } + } + + if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { + // interpolate + before = before_keyframe_index; + after = after_keyframe_index; + progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); + } else if (before_keyframe_index > -1) { + before = before_keyframe_index; + after = before_keyframe_index; + } else { + before = after_keyframe_index; + after = after_keyframe_index; + } +} + +bool EffectField::HasKeyframes() { + return (GetParentRow()->isKeyframing() && keyframes.size() > 1); +} + +void EffectField::ui_element_change() { + // TODO address this + //bool dragging_double = (type_ == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); + bool dragging_double = false; + ComboAction* ca = nullptr; + if (!dragging_double) ca = new ComboAction(); + //make_key_from_change(ca); + if (!dragging_double) olive::UndoStack.push(ca); + emit Changed(); +} + +/* +void EffectField::make_key_from_change(ComboAction* ca) { + if (GetParentRow()->isKeyframing()) { + GetParentRow()->set_keyframe_now(ca); + } else if (ca != nullptr) { + // set undo + ca->append(new EffectFieldUndo(this)); + } +} +*/ + +bool EffectField::IsEnabled() { + return enabled_; +} + +void EffectField::SetEnabled(bool e) { + enabled_ = e; + emit EnabledChanged(enabled_); +} diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h new file mode 100644 index 000000000..f5725e724 --- /dev/null +++ b/project/effectfields/effectfield.h @@ -0,0 +1,88 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef EFFECTFIELD_H +#define EFFECTFIELD_H + +#include +#include +#include + +#include "project/keyframe.h" + +class EffectRow; +class ComboAction; + +class EffectField : public QObject { + Q_OBJECT +public: + enum EffectFieldType { + EFFECT_FIELD_DOUBLE, + EFFECT_FIELD_COLOR, + EFFECT_FIELD_STRING, + EFFECT_FIELD_BOOL, + EFFECT_FIELD_COMBO, + EFFECT_FIELD_FONT, + EFFECT_FIELD_FILE + }; + + EffectField(EffectRow* parent, const QString& i, EffectFieldType t); + ~EffectField(); + + EffectRow* GetParentRow(); + + const EffectFieldType& type(); + const QString& id(); + + QVariant GetValueAt(double timecode); + void SetValueAt(double timecode, const QVariant& value); + + int GetColumnSpan(); + void SetColumnSpan(int i); + + virtual QVariant ConvertStringToValue(const QString& s) = 0; + virtual QString ConvertValueToString(const QVariant& v) = 0; + + double GetValidKeyframeHandlePosition(int key, bool post); + + bool IsEnabled(); + void SetEnabled(bool e); + QVector keyframes; + +public slots: + void ui_element_change(); +private: + EffectFieldType type_; + QString id_; + + bool HasKeyframes(); + double frameToTimecode(long frame); + long timecodeToFrame(double timecode); + void get_keyframe_data(double timecode, int& before, int& after, double& d); + + bool enabled_; + int colspan_; +signals: + void Changed(); + void Clicked(); + void EnabledChanged(bool); +}; + +#endif // EFFECTFIELD_H diff --git a/project/effectfields/filefield.cpp b/project/effectfields/filefield.cpp new file mode 100644 index 000000000..594cd6ff7 --- /dev/null +++ b/project/effectfields/filefield.cpp @@ -0,0 +1,22 @@ +#include "filefield.h" + +FileField::FileField(EffectRow* parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_FILE) +{ + +} + +QString FileField::GetFileAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant FileField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString FileField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/filefield.h b/project/effectfields/filefield.h new file mode 100644 index 000000000..edfcb280f --- /dev/null +++ b/project/effectfields/filefield.h @@ -0,0 +1,18 @@ +#ifndef FILEFIELD_H +#define FILEFIELD_H + +#include "effectfield.h" + +class FileField : public EffectField +{ + Q_OBJECT +public: + FileField(EffectRow* parent, const QString& id); + + QString GetFileAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // FILEFIELD_H diff --git a/project/effectfields/fontfield.cpp b/project/effectfields/fontfield.cpp new file mode 100644 index 000000000..faf88c55e --- /dev/null +++ b/project/effectfields/fontfield.cpp @@ -0,0 +1,22 @@ +#include "fontfield.h" + +FontField::FontField(EffectRow* parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_FONT) +{ + +} + +QString FontField::GetFontAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant FontField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString FontField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/fontfield.h b/project/effectfields/fontfield.h new file mode 100644 index 000000000..cf5b36c35 --- /dev/null +++ b/project/effectfields/fontfield.h @@ -0,0 +1,17 @@ +#ifndef FONTFIELD_H +#define FONTFIELD_H + +#include "effectfield.h" + +class FontField : public EffectField { + Q_OBJECT +public: + FontField(EffectRow* parent, const QString& id); + + QString GetFontAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // FONTFIELD_H diff --git a/project/effectfields/stringfield.cpp b/project/effectfields/stringfield.cpp new file mode 100644 index 000000000..77080607e --- /dev/null +++ b/project/effectfields/stringfield.cpp @@ -0,0 +1,22 @@ +#include "stringfield.h" + +StringField::StringField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_STRING) +{ + +} + +QString StringField::GetStringAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant StringField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString StringField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/stringfield.h b/project/effectfields/stringfield.h new file mode 100644 index 000000000..36028d891 --- /dev/null +++ b/project/effectfields/stringfield.h @@ -0,0 +1,18 @@ +#ifndef STRINGFIELD_H +#define STRINGFIELD_H + +#include "effectfield.h" + +class StringField : public EffectField +{ + Q_OBJECT +public: + StringField(EffectRow* parent, const QString& id); + + QString GetStringAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // STRINGFIELD_H diff --git a/project/effectgizmo.cpp b/project/effectgizmo.cpp index 047903259..b506eaf61 100644 --- a/project/effectgizmo.cpp +++ b/project/effectgizmo.cpp @@ -21,46 +21,49 @@ #include "effectgizmo.h" #include "ui/labelslider.h" -#include "effectfield.h" +#include "effectfields/doublefield.h" EffectGizmo::EffectGizmo(int type) : - x_field1(nullptr), - x_field_multi1(1.0), - y_field1(nullptr), - y_field_multi1(1.0), - x_field2(nullptr), - x_field_multi2(1.0), - y_field2(nullptr), - y_field_multi2(1.0), - type(type), - cursor(-1) + x_field1(nullptr), + x_field_multi1(1.0), + y_field1(nullptr), + y_field_multi1(1.0), + x_field2(nullptr), + x_field_multi2(1.0), + y_field2(nullptr), + y_field_multi2(1.0), + type(type), + cursor(-1) { - int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; - world_pos.resize(point_count); - screen_pos.resize(point_count); + int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; + world_pos.resize(point_count); + screen_pos.resize(point_count); - color = Qt::white; + color = Qt::white; } void EffectGizmo::set_previous_value() { - if (x_field1 != nullptr) static_cast(x_field1->ui_element)->set_previous_value(); - if (y_field1 != nullptr) static_cast(y_field1->ui_element)->set_previous_value(); - if (x_field2 != nullptr) static_cast(x_field2->ui_element)->set_previous_value(); - if (y_field2 != nullptr) static_cast(y_field2->ui_element)->set_previous_value(); + // TODO address this + /* + if (x_field1 != nullptr) static_cast(x_field1->ui_element)->set_previous_value(); + if (y_field1 != nullptr) static_cast(y_field1->ui_element)->set_previous_value(); + if (x_field2 != nullptr) static_cast(x_field2->ui_element)->set_previous_value(); + if (y_field2 != nullptr) static_cast(y_field2->ui_element)->set_previous_value(); + */ } int EffectGizmo::get_point_count() { - return world_pos.size(); + return world_pos.size(); } int EffectGizmo::get_type() { - return type; + return type; } int EffectGizmo::get_cursor() { - return cursor; + return cursor; } void EffectGizmo::set_cursor(int c) { - cursor = c; + cursor = c; } diff --git a/project/effectgizmo.h b/project/effectgizmo.h index 2f2dfbdfb..98a50962f 100644 --- a/project/effectgizmo.h +++ b/project/effectgizmo.h @@ -22,9 +22,9 @@ #define EFFECTGIZMO_H enum GizmoType { - GIZMO_TYPE_DOT, - GIZMO_TYPE_POLY, - GIZMO_TYPE_TARGET + GIZMO_TYPE_DOT, + GIZMO_TYPE_POLY, + GIZMO_TYPE_TARGET }; #define GIZMO_DOT_SIZE 2.5 @@ -36,37 +36,37 @@ enum GizmoType { #include #include -class EffectField; +class DoubleField; class EffectGizmo { public: - EffectGizmo(int type); + EffectGizmo(int type); - QVector world_pos; - QVector screen_pos; + QVector world_pos; + QVector screen_pos; - EffectField* x_field1; - double x_field_multi1; - EffectField* y_field1; - double y_field_multi1; - EffectField* x_field2; - double x_field_multi2; - EffectField* y_field2; - double y_field_multi2; + DoubleField* x_field1; + double x_field_multi1; + DoubleField* y_field1; + double y_field_multi1; + DoubleField* x_field2; + double x_field_multi2; + DoubleField* y_field2; + double y_field_multi2; - void set_previous_value(); + void set_previous_value(); - QColor color; - int get_point_count(); + QColor color; + int get_point_count(); - int get_type(); + int get_type(); - int get_cursor(); - void set_cursor(int c); + int get_cursor(); + void set_cursor(int c); private: - int type; - int cursor; + int type; + int cursor; }; #endif // EFFECTGIZMO_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp index 11ef3f23f..51a3a429b 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -37,278 +37,251 @@ #include "ui/clickablelabel.h" EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row, bool keyframable) : - parent_effect(parent), - savable(save), - keyframing(false), - ui(uilayout), - name(n), - ui_row(row), - just_made_unsafe_keyframe(false) + parent_effect(parent), + savable(save), + keyframing(false), + ui(uilayout), + name_(n), + ui_row(row), + just_made_unsafe_keyframe(false) { - label = new ClickableLabel(name + ":"); + label = new ClickableLabel(name_ + ":"); - ui->addWidget(label, row, 0); + ui->addWidget(label, row, 0); - column_count = 1; + column_count = 1; - keyframe_nav = nullptr; - if (parent_effect->meta != nullptr - && parent_effect->meta->type != EFFECT_TYPE_TRANSITION - && keyframable) { - connect(label, SIGNAL(clicked()), this, SLOT(focus_row())); + keyframe_nav = nullptr; + if (parent_effect->meta != nullptr + && parent_effect->meta->type != EFFECT_TYPE_TRANSITION + && keyframable) { + connect(label, SIGNAL(clicked()), this, SLOT(FocusRow())); - keyframe_nav = new KeyframeNavigator(); - connect(keyframe_nav, SIGNAL(goto_previous_key()), this, SLOT(goto_previous_key())); - connect(keyframe_nav, SIGNAL(toggle_key()), this, SLOT(toggle_key())); - connect(keyframe_nav, SIGNAL(goto_next_key()), this, SLOT(goto_next_key())); - connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(set_keyframe_enabled(bool))); - connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(focus_row())); - ui->addWidget(keyframe_nav, row, 6); - } + keyframe_nav = new KeyframeNavigator(); + connect(keyframe_nav, SIGNAL(GoToPreviousKeyframe()), this, SLOT(GoToPreviousKeyframe())); + connect(keyframe_nav, SIGNAL(ToggleKeyframe()), this, SLOT(ToggleKeyframe())); + connect(keyframe_nav, SIGNAL(GoToNextKeyframe()), this, SLOT(GoToNextKeyframe())); + connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(SetKeyframingEnabled(bool))); + connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(FocusRow())); + ui->addWidget(keyframe_nav, row, 6); + } } EffectRow::~EffectRow() { - for (int i=0;isetParent(this); + fields_.append(field); } bool EffectRow::isKeyframing() { - return keyframing; + return keyframing; } void EffectRow::setKeyframing(bool b) { - if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) { - keyframing = b; - if (keyframe_nav != nullptr) { - keyframe_nav->enable_keyframes(b); - } - } + if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) { + keyframing = b; + if (keyframe_nav != nullptr) { + keyframe_nav->enable_keyframes(b); + } + } } -void EffectRow::set_keyframe_enabled(bool enabled) { - if (enabled) { - ComboAction* ca = new ComboAction(); - ca->append(new SetKeyframing(this, true)); - set_keyframe_now(ca); - olive::UndoStack.push(ca); - } else { - if (QMessageBox::question(panel_effect_controls, - tr("Disable Keyframes"), - tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - // clear - ComboAction* ca = new ComboAction(); - for (int i=0;ikeyframes.size();j++) { - ca->append(new KeyframeDelete(f, 0)); - } - } - ca->append(new SetKeyframing(this, false)); - olive::UndoStack.push(ca); - panel_effect_controls->update_keyframes(); - } else { - setKeyframing(true); - } - } +void EffectRow::SetKeyframingEnabled(bool enabled) { + if (enabled) { + ComboAction* ca = new ComboAction(); + ca->append(new SetKeyframing(this, true)); + set_keyframe_now(ca); + olive::UndoStack.push(ca); + } else { + if (QMessageBox::question(panel_effect_controls, + tr("Disable Keyframes"), + tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + // clear + ComboAction* ca = new ComboAction(); + for (int i=0;ikeyframes.size();j++) { + ca->append(new KeyframeDelete(f, 0)); + } + } + ca->append(new SetKeyframing(this, false)); + olive::UndoStack.push(ca); + panel_effect_controls->update_keyframes(); + } else { + setKeyframing(true); + } + } } -void EffectRow::goto_previous_key() { - long key = LONG_MIN; +void EffectRow::GoToPreviousKeyframe() { + long key = LONG_MIN; Clip* c = parent_effect->parent_clip; - for (int i=0;ikeyframes.size();j++) { + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp < olive::ActiveSequence->playhead) { - key = qMax(comp, key); - } - } - } - if (key != LONG_MIN) panel_sequence_viewer->seek(key); + if (comp < olive::ActiveSequence->playhead) { + key = qMax(comp, key); + } + } + } + if (key != LONG_MIN) panel_sequence_viewer->seek(key); } -void EffectRow::toggle_key() { - QVector key_fields; - QVector key_field_index; +void EffectRow::ToggleKeyframe() { + QVector key_fields; + QVector key_field_index; Clip* c = parent_effect->parent_clip; - for (int j=0;jkeyframes.size();i++) { + for (int j=0;jkeyframes.size();i++) { long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time; - if (comp == olive::ActiveSequence->playhead) { - key_fields.append(f); - key_field_index.append(i); - } - } - } + if (comp == olive::ActiveSequence->playhead) { + key_fields.append(f); + key_field_index.append(i); + } + } + } - ComboAction* ca = new ComboAction(); - if (key_fields.size() == 0) { - // keyframe doesn't exist, set one - set_keyframe_now(ca); - } else { - for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); - } - } - olive::UndoStack.push(ca); - update_ui(false); + ComboAction* ca = new ComboAction(); + if (key_fields.size() == 0) { + // keyframe doesn't exist, set one + set_keyframe_now(ca); + } else { + for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); + } + } + olive::UndoStack.push(ca); + update_ui(false); } -void EffectRow::goto_next_key() { - long key = LONG_MAX; +void EffectRow::GoToNextKeyframe() { + long key = LONG_MAX; Clip* c = parent_effect->parent_clip; - for (int i=0;ikeyframes.size();j++) { + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp > olive::ActiveSequence->playhead) { - key = qMin(comp, key); - } - } - } - if (key != LONG_MAX) panel_sequence_viewer->seek(key); + if (comp > olive::ActiveSequence->playhead) { + key = qMin(comp, key); + } + } + } + if (key != LONG_MAX) panel_sequence_viewer->seek(key); } -void EffectRow::focus_row() { - panel_graph_editor->set_row(this); +void EffectRow::FocusRow() { + panel_graph_editor->set_row(this); } +/* EffectField* EffectRow::add_field(int type, const QString& id, int colspan) { - EffectField* field = new EffectField(this, type, id); - if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row())); - fields.append(field); - QWidget* element = field->get_ui_element(); - ui->addWidget(element, ui_row, column_count, 1, colspan); - column_count++; - connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed())); - return field; + EffectField* field = new EffectField(this, type, id); + if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row())); + fields_.append(field); + QWidget* element = field->get_ui_element(); + ui->addWidget(element, ui_row, column_count, 1, colspan); + column_count++; + connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed())); + return field; } +*/ void EffectRow::add_widget(QWidget* w) { - widgets.append(w); - ui->addWidget(w, ui_row, column_count); - column_count++; + widgets.append(w); + ui->addWidget(w, ui_row, column_count); + column_count++; } void EffectRow::set_keyframe_now(ComboAction* ca) { + // TODO address this... + /* long time = olive::ActiveSequence->playhead - parent_effect->parent_clip->timeline_in() + parent_effect->parent_clip->clip_in(); - if (!just_made_unsafe_keyframe) { - EffectKeyframe key; - key.time = time; + if (!just_made_unsafe_keyframe) { + EffectKeyframe key; + key.time = time; - unsafe_keys.resize(fieldCount()); - unsafe_old_data.resize(fieldCount()); - key_is_new.resize(fieldCount()); + unsafe_keys.resize(fieldCount()); + unsafe_old_data.resize(fieldCount()); + key_is_new.resize(fieldCount()); - for (int i=0;ikeyframes.size();j++) { - if (f->keyframes.at(j).time == time) { - exist_key = j; - } else if (f->keyframes.at(j).time < time - && f->keyframes.at(closest_key).time < f->keyframes.at(j).time) { - closest_key = j; - } - } - if (exist_key == -1) { - key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type; - key.data = f->get_current_data();//f->keyframes.at(closest_key).data; - unsafe_keys[i] = f->keyframes.size(); - f->keyframes.append(key); - key_is_new[i] = true; - } else { - unsafe_keys[i] = exist_key; - key_is_new[i] = false; - } - unsafe_old_data[i] = f->get_current_data(); - } - just_made_unsafe_keyframe = true; - } + int exist_key = -1; + int closest_key = 0; + for (int j=0;jkeyframes.size();j++) { + if (f->keyframes.at(j).time == time) { + exist_key = j; + } else if (f->keyframes.at(j).time < time + && f->keyframes.at(closest_key).time < f->keyframes.at(j).time) { + closest_key = j; + } + } + if (exist_key == -1) { + key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type; + key.data = f->GetCurrentValue(); + unsafe_keys[i] = f->keyframes.size(); + f->keyframes.append(key); + key_is_new[i] = true; + } else { + unsafe_keys[i] = exist_key; + key_is_new[i] = false; + } + unsafe_old_data[i] = f->GetCurrentValue(); + } + just_made_unsafe_keyframe = true; + } - for (int i=0;ikeyframes[unsafe_keys.at(i)].data = field(i)->get_current_data(); - } + for (int i=0;ikeyframes[unsafe_keys.at(i)].data = field(i)->GetCurrentValue(); + } - if (ca != nullptr) { - for (int i=0;iappend(new KeyframeFieldSet(field(i), unsafe_keys.at(i))); - ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->get_current_data())); - } - unsafe_keys.clear(); - unsafe_old_data.clear(); - just_made_unsafe_keyframe = false; - } + if (ca != nullptr) { + for (int i=0;iappend(new KeyframeFieldSet(field(i), unsafe_keys.at(i))); + ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->GetCurrentValue())); + } + unsafe_keys.clear(); + unsafe_old_data.clear(); + just_made_unsafe_keyframe = false; + } - panel_effect_controls->update_keyframes(); - - - - - - /*if (ca != nullptr) { - just_made_unsafe_keyframe = false; - } else { - if (!just_made_unsafe_keyframe) { - just_made_unsafe_keyframe = true; - } - }*/ - - - /*int index = -1; - long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in; - for (int j=0;jkeyframes.size();i++) { - if (f->keyframes.at(i).time == time) { - index = i; - break; - } - } - } - - KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe); - - if (ca != nullptr) { - just_made_unsafe_keyframe = false; - ca->append(ks); - } else { - if (index == -1) just_made_unsafe_keyframe = true; - ks->redo(); - delete ks; - } - - panel_effect_controls->update_keyframes();*/ + panel_effect_controls->update_keyframes(); + */ } void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { - for (int j=0;jkeyframes.size();i++) { - if (f->keyframes.at(i).time == time) { - ca->append(new KeyframeDelete(f, i)); - break; - } - } - } + for (int j=0;jkeyframes.size();i++) { + if (f->keyframes.at(i).time == time) { + ca->append(new KeyframeDelete(f, i)); + break; + } + } + } } -const QString &EffectRow::get_name() { - return name; +const QString &EffectRow::name() { + return name_; } EffectField* EffectRow::field(int i) { - return fields.at(i); + return fields_.at(i); } int EffectRow::fieldCount() { - return fields.size(); + return fields_.size(); } diff --git a/project/effectrow.h b/project/effectrow.h index 845286d6e..9b61ac6c3 100644 --- a/project/effectrow.h +++ b/project/effectrow.h @@ -1,4 +1,4 @@ -/*** +/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team @@ -34,47 +34,51 @@ class QHBoxLayout; class KeyframeNavigator; class ClickableLabel; +#include "effectfields.h" + class EffectRow : public QObject { - Q_OBJECT + Q_OBJECT public: - EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true); - ~EffectRow(); - EffectField* add_field(int type, const QString &id, int colspan = 1); - void add_widget(QWidget *w); - EffectField* field(int i); - int fieldCount(); - void set_keyframe_now(ComboAction *ca); - void delete_keyframe_at_time(ComboAction *ca, long time); - ClickableLabel* label; - Effect* parent_effect; - bool savable; - const QString& get_name(); + EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true); + ~EffectRow(); - bool isKeyframing(); - void setKeyframing(bool); + void AddField(EffectField* field); + + void add_widget(QWidget *w); + EffectField* field(int i); + int fieldCount(); + void set_keyframe_now(ComboAction *ca); + void delete_keyframe_at_time(ComboAction *ca, long time); + ClickableLabel* label; + Effect* parent_effect; + bool savable; + const QString& name(); + + bool isKeyframing(); + void setKeyframing(bool); public slots: - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); - void focus_row(); + void GoToPreviousKeyframe(); + void ToggleKeyframe(); + void GoToNextKeyframe(); + void FocusRow(); private slots: - void set_keyframe_enabled(bool); + void SetKeyframingEnabled(bool); private: - bool keyframing; - QGridLayout* ui; - QString name; - int ui_row; - QVector fields; - QVector widgets; + bool keyframing; + QGridLayout* ui; + QString name_; + int ui_row; + QVector fields_; + QVector widgets; - KeyframeNavigator* keyframe_nav; + KeyframeNavigator* keyframe_nav; - bool just_made_unsafe_keyframe; - QVector unsafe_keys; - QVector unsafe_old_data; - QVector key_is_new; + bool just_made_unsafe_keyframe; + QVector unsafe_keys; + QVector unsafe_old_data; + QVector key_is_new; - int column_count; + int column_count; }; #endif // EFFECTROW_H diff --git a/project/keyframe.cpp b/project/keyframe.cpp index 5811dc90c..64a36ce2d 100644 --- a/project/keyframe.cpp +++ b/project/keyframe.cpp @@ -22,45 +22,45 @@ #include -#include "effectfield.h" +#include "effectfields.h" #include "undo.h" #include "panels/panels.h" EffectKeyframe::EffectKeyframe() { - pre_handle_x = -40; - pre_handle_y = 0; - post_handle_x = 40; - post_handle_y = 0; + pre_handle_x = -40; + pre_handle_y = 0; + post_handle_x = 40; + post_handle_y = 0; } void delete_keyframes(QVector& selected_key_fields, QVector &selected_keys) { - QVector fields; - QVector key_indices; + QVector fields; + QVector key_indices; - for (int i=0;i 0) { - ComboAction* ca = new ComboAction(); - for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); - } - olive::UndoStack.push(ca); - selected_keys.clear(); - selected_key_fields.clear(); - update_ui(false); - } + if (fields.size() > 0) { + ComboAction* ca = new ComboAction(); + for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); + } + olive::UndoStack.push(ca); + selected_keys.clear(); + selected_key_fields.clear(); + update_ui(false); + } } diff --git a/project/transition.cpp b/project/transition.cpp index cb724f4fc..ecc53eb27 100644 --- a/project/transition.cpp +++ b/project/transition.cpp @@ -42,21 +42,21 @@ #include Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : - Effect(c, em), secondary_clip(s), - length(30) + Effect(c, em), + secondary_clip(s) { - length_field = add_row(tr("Length"), false)->add_field(EFFECT_FIELD_DOUBLE, "length"); + EffectRow* length_row = add_row(tr("Length"), false, false); + length_field = new DoubleField(length_row, "length"); + length_field->SetDefault(30); + length_field->SetMinimum(0); + length_field->SetDisplayType(LabelSlider::LABELSLIDER_FRAMENUMBER); + length_field->SetFrameRate(parent_clip->sequence == nullptr ? + parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); - length_field->set_double_default_value(30); - length_field->set_double_minimum_value(0); - - LabelSlider* length_ui_ele = static_cast(length_field->ui_element); - length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER); - length_ui_ele->set_frame_rate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); } TransitionPtr Transition::copy(Clip *c, Clip *s) { - return Transition::Create(c, s, meta, length); + return Transition::Create(c, s, meta, get_true_length()); } void Transition::save(QXmlStreamWriter &stream) { @@ -64,20 +64,19 @@ void Transition::save(QXmlStreamWriter &stream) { Effect::save(stream); } -void Transition::set_length(long l) { - length = l; - length_field->set_double_value(l); +void Transition::set_length(int l) { + length_field->SetValueAt(0, l); } -long Transition::get_true_length() { - return length; +int Transition::get_true_length() { + return length_field->GetValueAt(0).toInt(); } -long Transition::get_length() { +int Transition::get_length() { if (secondary_clip != nullptr) { - return length * 2; + return get_true_length() * 2; } - return length; + return get_true_length(); } Clip* Transition::get_opened_clip() { @@ -99,7 +98,6 @@ Clip* Transition::get_closed_clip() { } void Transition::set_length_from_slider() { - set_length(length_field->get_double_value(0)); update_ui(false); } @@ -114,7 +112,7 @@ TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em) case TRANSITION_INTERNAL_LINEARFADE: return TransitionPtr(new LinearFadeTransition(c, s, em)); case TRANSITION_INTERNAL_EXPONENTIALFADE: return TransitionPtr(new ExponentialFadeTransition(c, s, em)); case TRANSITION_INTERNAL_LOGARITHMICFADE: return TransitionPtr(new LogarithmicFadeTransition(c, s, em)); - case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em)); + //case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em)); } } else { qCritical() << "Invalid transition data"; diff --git a/project/transition.h b/project/transition.h index a88f55bc9..ecce355a3 100644 --- a/project/transition.h +++ b/project/transition.h @@ -34,7 +34,7 @@ enum TransitionInternal { TRANSITION_INTERNAL_LINEARFADE, TRANSITION_INTERNAL_EXPONENTIALFADE, TRANSITION_INTERNAL_LOGARITHMICFADE, - TRANSITION_INTERNAL_CUBE, + //TRANSITION_INTERNAL_CUBE, TRANSITION_INTERNAL_COUNT }; @@ -50,9 +50,9 @@ public: virtual void save(QXmlStreamWriter& stream) override; - void set_length(long l); - long get_true_length(); - long get_length(); + void set_length(int l); + int get_true_length(); + int get_length(); Clip* get_opened_clip(); Clip* get_closed_clip(); @@ -62,8 +62,7 @@ public: private slots: void set_length_from_slider(); private: - long length; // used only for transitions - EffectField* length_field; + DoubleField* length_field; }; #endif // TRANSITION_H diff --git a/project/undo.cpp b/project/undo.cpp index 3d30b5e69..fca7f6ff6 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -666,25 +666,21 @@ void KeyframeDelete::doRedo() { field->keyframes.removeAt(index); } -EffectFieldUndo::EffectFieldUndo(EffectField* f) { - field = f; - done = true; - - old_val = field->get_previous_data(); - new_val = field->get_current_data(); -} +/* +EffectFieldUndo::EffectFieldUndo(EffectField* f, const QVariant& old_data, const QVariant new_data) : + field(f), + old_val(old_data), + new_val(new_data) +{} void EffectFieldUndo::doUndo() { - field->set_current_data(old_val); - done = false; - + field->SetCurrentValue(old_val); } void EffectFieldUndo::doRedo() { - if (!done) { - field->set_current_data(new_val); - } + field->SetCurrentValue(new_val); } +*/ SetClipProperty::SetClipProperty(SetClipPropertyType type) : type_(type) {} diff --git a/project/undo.h b/project/undo.h index c63bc9e98..273149794 100644 --- a/project/undo.h +++ b/project/undo.h @@ -23,7 +23,7 @@ #include "project/projectelements.h" #include "project/selection.h" -#include "project/effectfield.h" +#include "project/effectfields/effectfield.h" #include "ui/labelslider.h" #include "ui/sourcetable.h" @@ -352,7 +352,7 @@ private: class EffectFieldUndo : public OliveAction { public: - EffectFieldUndo(EffectField* field); + EffectFieldUndo(EffectField* field, const QVariant &old_data, const QVariant new_data); virtual void doUndo() override; virtual void doRedo() override; private: diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 4f6a08990..68d91073c 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -115,11 +115,11 @@ void process_effect(Clip* c, bool& texture_failed, int data) { if (e->is_enabled()) { - if (e->enable_coords) { + if (e->Flags() & Effect::CoordsFlag) { e->process_coords(timecode, coords, data); } - bool can_process_shaders = (e->enable_shader && olive::CurrentRuntimeConfig.shaders_are_enabled); - if (can_process_shaders || e->enable_superimpose) { + bool can_process_shaders = ((e->Flags() & Effect::ShaderFlag) && olive::CurrentRuntimeConfig.shaders_are_enabled); + if (can_process_shaders || (e->Flags() & Effect::SuperimposeFlag)) { e->startEffect(); if (can_process_shaders && e->is_glsl_linked()) { for (int i=0;igetIterations();i++) { @@ -128,7 +128,7 @@ void process_effect(Clip* c, fbo_switcher = !fbo_switcher; } } - if (e->enable_superimpose) { + if (e->Flags() & Effect::SuperimposeFlag) { GLuint superimpose_texture = e->process_superimpose(timecode); if (superimpose_texture == 0) { @@ -399,7 +399,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0.0; coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0; coords.textureTopLeftQ = coords.textureTopRightQ = coords.textureTopLeftQ = coords.textureBottomLeftQ = 1; - coords.blendmode = BLEND_MODE_NORMAL; + coords.blendmode = -1; coords.opacity = 1.0; // if auto-scale is enabled, auto-scale the clip @@ -615,6 +615,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } + /* // visually update all the keyframe values if (c->sequence == params.seq) { // only if you can currently see them double ts = (playhead - c->timeline_in(true) + c->clip_in(true))/s->frame_rate; @@ -628,6 +629,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } } + */ } } else { params.texture_failed = true; diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 86ae1aba9..3f51dda3f 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -245,7 +245,7 @@ void GraphView::paintEvent(QPaintEvent *) { for (int i=row->fieldCount()-1;i>=0;i--) { EffectField* field = row->field(i); - if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { // sort keyframes by time QVector sorted_keys = sort_keys_from_field(field); @@ -266,8 +266,8 @@ void GraphView::paintEvent(QPaintEvent *) { } else { const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1)); - double pre_handle = field->get_validated_keyframe_handle(sorted_keys.at(j), false); - double last_post_handle = field->get_validated_keyframe_handle(sorted_keys.at(j-1), true); + double pre_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j), false); + double last_post_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j-1), true); if (last_key.type == EFFECT_KEYFRAME_HOLD) { // hold @@ -387,7 +387,7 @@ void GraphView::mousePressEvent(QMouseEvent *event) { } else { for (int i=0;ifieldCount();i++) { EffectField* field = row->field(i); - if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { for (int j=0;jkeyframes.size();j++) { const EffectKeyframe& key = field->keyframes.at(j); int key_x = get_screen_x(key.time); @@ -833,7 +833,7 @@ void GraphView::set_row(EffectRow *r) { if (row != nullptr) { field_visibility.resize(row->fieldCount()); for (int i=0;ifieldCount();i++) { - field_visibility[i] = row->field(i)->is_enabled(); + field_visibility[i] = row->field(i)->IsEnabled(); } visible_in = row->parent_effect->parent_clip->timeline_in(); set_view_to_all(); diff --git a/ui/graphview.h b/ui/graphview.h index 203e80202..bc1e96473 100644 --- a/ui/graphview.h +++ b/ui/graphview.h @@ -25,7 +25,7 @@ #include #include "project/effectrow.h" -#include "project/effectfield.h" +#include "project/effectfields.h" QColor get_curve_color(int index, int length); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index fcca08c26..4c00dd862 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -250,7 +250,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) { EffectRow* row = rows.at(i); - row->focus_row(); + row->FocusRow(); for (int k=0;kfieldCount();k++) { EffectField* f = row->field(k); @@ -376,7 +376,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { if (panel_timeline->snapping) { for (int i=0;iparent_row->parent_effect->parent_clip; + Clip* c = field->GetParentRow()->parent_effect->parent_clip; long key_time = old_key_vals.at(i) + frame_diff - c->clip_in() + c->timeline_in(); long key_eval = key_time; if (panel_timeline->snap_to_point(olive::ActiveSequence->playhead, &key_eval)) { diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 9791def51..9319d4528 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -56,7 +56,7 @@ void LabelSlider::set_frame_rate(double d) { frame_rate = d; } -void LabelSlider::set_display_type(int type) { +void LabelSlider::set_display_type(const DisplayType& type) { display_type = type; setText(valueToString()); } @@ -112,8 +112,9 @@ QString LabelSlider::valueToString() { return db_str; } + default: + return QString::number(v, 'f', decimal_places); } - return QString::number(v, 'f', decimal_places); } } diff --git a/ui/labelslider.h b/ui/labelslider.h index ae0eae0c0..5c203eaa6 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -24,13 +24,6 @@ #include #include -enum LabelSliderDisplayType { - LABELSLIDER_NORMAL, - LABELSLIDER_FRAMENUMBER, - LABELSLIDER_PERCENT, - LABELSLIDER_DECIBEL -}; - /** * @brief The LabelSlider class * @@ -53,6 +46,13 @@ public: */ void set_frame_rate(double d); + enum DisplayType { + LABELSLIDER_NORMAL, + LABELSLIDER_FRAMENUMBER, + LABELSLIDER_PERCENT, + LABELSLIDER_DECIBEL + }; + /** * @brief Sets the way to display the value * @@ -65,9 +65,9 @@ public: * * @param type * - * The display type to set to. Should be a member of `enum LabelSliderDisplayType`. + * The display type to set to. */ - void set_display_type(int type); + void set_display_type(const DisplayType& type); /** * @brief Set the value @@ -205,7 +205,7 @@ private: bool set; - int display_type; + DisplayType display_type; double frame_rate; diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index 7d6461ed4..f56bcf1cc 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -22,41 +22,71 @@ #include +/* TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) { - setUndoRedoEnabled(false); - connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals())); - connect(this, SIGNAL(updateSelf()), this, SLOT(updateText())); + setUndoRedoEnabled(false); + connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals())); + connect(this, SIGNAL(updateSelf()), this, SLOT(updateText())); } const QString& TextEditEx::getPlainTextEx() { - return text; + return text; } void TextEditEx::setPlainTextEx(const QString &t) { - previousText = text; - text = t; - emit updateSelf(); + previousText = text; + text = t; + emit updateSelf(); } const QString &TextEditEx::getPreviousValue() { - return previousText; + return previousText; } void TextEditEx::updateInternals() { - previousText = text; - text = toPlainText(); + previousText = text; + text = toPlainText(); } void TextEditEx::updateText() { - blockSignals(true); + blockSignals(true); - int pos = textCursor().position(); + int pos = textCursor().position(); - setPlainText(text); + setPlainText(text); - QTextCursor newCursor(document()); - newCursor.setPosition(pos); - setTextCursor(newCursor); + QTextCursor newCursor(document()); + newCursor.setPosition(pos); + setTextCursor(newCursor); - blockSignals(false); + blockSignals(false); +} +*/ + +#include + +#include "dialogs/texteditdialog.h" +#include "mainwindow.h" + +TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) +{ + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); +} + +void TextEditEx::text_edit_menu() { + QMenu menu; + + menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit())); + + menu.exec(QCursor::pos()); +} + +void TextEditEx::open_text_edit() { + TextEditDialog ted(olive::MainWindow, this->toHtml()); + ted.exec(); + QString result = ted.get_string(); + if (!result.isEmpty()) { + setHtml(result); + } } diff --git a/ui/texteditex.h b/ui/texteditex.h index b345859a6..aca586034 100644 --- a/ui/texteditex.h +++ b/ui/texteditex.h @@ -23,21 +23,31 @@ #include +/* class TextEditEx : public QTextEdit { - Q_OBJECT + Q_OBJECT public: - TextEditEx(QWidget* parent = 0); - void setPlainTextEx(const QString &text); - const QString& getPreviousValue(); - const QString& getPlainTextEx(); + TextEditEx(QWidget* parent = 0); + void setPlainTextEx(const QString &text); + const QString& getPreviousValue(); + const QString& getPlainTextEx(); signals: - void updateSelf(); + void updateSelf(); private slots: - void updateInternals(); - void updateText(); + void updateInternals(); + void updateText(); private: - QString previousText; - QString text; + QString previousText; + QString text; +}; +*/ + +class TextEditEx : public QTextEdit { +public: + TextEditEx(QWidget* parent); +private slots: + void text_edit_menu(); + void open_text_edit(); }; #endif // TEXTEDITEX_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 832412fec..828f2d5e1 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1040,7 +1040,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { { c->set_name(tr("Bars")); EffectPtr e = Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT)); - e->row(0)->field(0)->set_combo_index(1); + + // Auto-select bars + SolidEffect* solid_effect = static_cast(e.get()); + solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS); + c->effects.append(e); } break; diff --git a/ui/updatenotification.cpp b/ui/updatenotification.cpp index 38d2a8f2d..aca2f47b7 100644 --- a/ui/updatenotification.cpp +++ b/ui/updatenotification.cpp @@ -14,7 +14,7 @@ UpdateNotification::UpdateNotification() void UpdateNotification::check() { -#if defined(_WIN32) || defined(__APPLE__) +#if defined(GITHASH) && (defined(_WIN32) || defined(__APPLE__)) QNetworkAccessManager* manager = new QNetworkAccessManager(); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(finished_slot(QNetworkReply *)));