decoupled effectfield UI from backend

This commit is contained in:
itsmattkc
2019-03-12 19:33:01 +11:00
parent 0f3d91b7b3
commit 170fe9bd01
73 changed files with 3230 additions and 2971 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector<Clip *> 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);
+6 -3
View File
@@ -48,7 +48,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector<Clip*> 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<Clip*> 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;
+11 -10
View File
@@ -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 <QtMath>
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<qint16>();
// 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<qint16> (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint16 right_sample = static_cast<qint16> (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
left_noise_sample = mix_audio_sample(left_noise_sample, left_sample);
+5 -5
View File
@@ -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
+47 -47
View File
@@ -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);
}
+17 -17
View File
@@ -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
+5 -7
View File
@@ -23,14 +23,12 @@
#include <QOpenGLFunctions>
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;
}
}
-33
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#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;
}
+14 -14
View File
@@ -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;i<nb_bytes;i+=4) {
if (fill_type->get_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;i<nb_bytes;i+=4) {
if (fill_type->GetValueAt(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];
}
}
}
+4 -4
View File
@@ -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
+126 -126
View File
@@ -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<f0rInitFunc>(LibAddress(handle, "f0r_init"));
init();
f0rInitFunc init = reinterpret_cast<f0rInitFunc>(LibAddress(handle, "f0r_init"));
init();
construct_module();
construct_module();
f0r_plugin_info_t info;
f0rGetPluginInfo info_func = reinterpret_cast<f0rGetPluginInfo>(LibAddress(handle, "f0r_get_plugin_info"));
info_func(&info);
f0r_plugin_info_t info;
f0rGetPluginInfo info_func = reinterpret_cast<f0rGetPluginInfo>(LibAddress(handle, "f0r_get_plugin_info"));
info_func(&info);
param_count = info.num_params;
param_count = info.num_params;
get_param_info = reinterpret_cast<f0rGetParamInfo>(LibAddress(handle, "f0r_get_param_info"));
for (int i=0;i<param_count;i++) {
f0r_param_info_t param_info;
get_param_info(&param_info, i);
get_param_info = reinterpret_cast<f0rGetParamInfo>(LibAddress(handle, "f0r_get_param_info"));
for (int i=0;i<param_count;i++) {
f0r_param_info_t param_info;
get_param_info(&param_info, i);
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:
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<f0rDeinitFunc>(LibAddress(handle, "f0r_deinit"));
deinit();
if (handle != nullptr) {
f0rDeinitFunc deinit = reinterpret_cast<f0rDeinitFunc>(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<f0rUpdateFunc>(LibAddress(handle, "f0r_update"));
f0rUpdateFunc update_func = reinterpret_cast<f0rUpdateFunc>(LibAddress(handle, "f0r_update"));
for (int i=0;i<param_count;i++) {
EffectRow* param_row = row(i);
for (int i=0;i<param_count;i++) {
EffectRow* param_row = row(i);
f0r_param_info_t param_info;
get_param_info(&param_info, i);
f0r_param_info_t param_info;
get_param_info(&param_info, i);
f0rSetParamValue set_param = reinterpret_cast<f0rSetParamValue>(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<f0rSetParamValue>(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<QColor>();
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<uint32_t*>(input), reinterpret_cast<uint32_t*>(output));
update_func(instance, timecode, reinterpret_cast<uint32_t*>(input), reinterpret_cast<uint32_t*>(output));
}
void Frei0rEffect::refresh() {
destruct_module();
construct_module();
destruct_module();
construct_module();
}
void Frei0rEffect::destruct_module() {
if (open) {
f0rDestructFunc destruct = reinterpret_cast<f0rDestructFunc>(LibAddress(handle, "f0r_destruct"));
destruct(instance);
if (open) {
f0rDestructFunc destruct = reinterpret_cast<f0rDestructFunc>(LibAddress(handle, "f0r_destruct"));
destruct(instance);
open = false;
}
open = false;
}
}
void Frei0rEffect::construct_module() {
f0rConstructFunc construct = reinterpret_cast<f0rConstructFunc>(LibAddress(handle, "f0r_construct"));
f0rConstructFunc construct = reinterpret_cast<f0rConstructFunc>(LibAddress(handle, "f0r_construct"));
instance = construct(parent_clip->media_width(), parent_clip->media_height());
open = true;
open = true;
}
#endif
+23 -25
View File
@@ -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;i<nb_bytes;i+=4) {
double pan_field_val = pan_val->get_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;i<nb_bytes;i+=4) {
double pan_field_val = pan_val->GetDoubleAt(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);
}
}
+4 -4
View File
@@ -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
+42 -44
View File
@@ -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<int32_t>::max();
for (int i=0;i<RANDOM_VAL_SIZE;i++) {
random_vals[i] = static_cast<double>(this->randomNumber<int32_t>()) / limit;
}
const auto limit = std::numeric_limits<int32_t>::max();
for (int i=0;i<RANDOM_VAL_SIZE;i++) {
random_vals[i] = static_cast<double>(this->randomNumber<int32_t>()) / 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;i<lim;i++) {
int offset = 6*i;
xoff += qSin((x+random_vals[offset])*random_vals[offset+1]);
yoff += qSin((x+random_vals[offset+2])*random_vals[offset+3]);
rotoff += qSin((x+random_vals[offset+4])*random_vals[offset+5]);
}
for (int i=0;i<lim;i++) {
int offset = 6*i;
xoff += qSin((x+random_vals[offset])*random_vals[offset+1]);
yoff += qSin((x+random_vals[offset+2])*random_vals[offset+3]);
rotoff += qSin((x+random_vals[offset+4])*random_vals[offset+5]);
}
xoff *= multiplier;
yoff *= multiplier;
rotoff *= rotmult;
xoff *= multiplier;
yoff *= multiplier;
rotoff *= rotmult;
coords.vertexTopLeftX += xoff;
coords.vertexTopRightX += xoff;
coords.vertexBottomLeftX += xoff;
coords.vertexBottomRightX += xoff;
coords.vertexTopLeftX += xoff;
coords.vertexTopRightX += xoff;
coords.vertexBottomLeftX += xoff;
coords.vertexBottomRightX += xoff;
coords.vertexTopLeftY += yoff;
coords.vertexTopRightY += yoff;
coords.vertexBottomLeftY += yoff;
coords.vertexBottomRightY += yoff;
coords.vertexTopLeftY += yoff;
coords.vertexTopRightY += yoff;
coords.vertexBottomLeftY += yoff;
coords.vertexBottomRightY += yoff;
glRotatef(rotoff, 0, 0, 1);
glRotatef(rotoff, 0, 0, 1);
}
+5 -5
View File
@@ -26,16 +26,16 @@
#define RANDOM_VAL_SIZE 30
class ShakeEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
ShakeEffect(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords& coords, int data);
EffectField* intensity_val;
EffectField* rotation_val;
EffectField* frequency_val;
DoubleField* intensity_val;
DoubleField* rotation_val;
DoubleField* frequency_val;
private:
double random_vals[RANDOM_VAL_SIZE];
double random_vals[RANDOM_VAL_SIZE];
};
#endif // SHAKEEFFECT_H
+156 -145
View File
@@ -30,168 +30,179 @@
#include "project/clip.h"
#include "project/sequence.h"
#define SOLID_TYPE_COLOR 0
#define SOLID_TYPE_BARS 1
#define SOLID_TYPE_CHECKERBOARD 2
const int SMPTE_BARS = 7;
const int SMPTE_STRIP_COUNT = 3;
const int SMPTE_LOWER_BARS = 4;
#define SMPTE_BARS 7
#define SMPTE_STRIP_COUNT 3
#define SMPTE_LOWER_BARS 4
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
{
SetFlags(Effect::SuperimposeFlag);
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
enable_superimpose = true;
// Field for solid type
EffectRow* type_row = add_row(tr("Type"));
solid_type = new ComboField(type_row, "type");
solid_type->AddItem(tr("Solid Color"), SOLID_TYPE_COLOR);
solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS);
solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD);
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<QComboBox*>(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;i<SMPTE_BARS;i++) {
bar_x = bar_width*i;
switch (i) {
case 0:
first_color = QColor(192, 192, 192);
second_color = QColor(0, 0, 192);
break;
case 1:
first_color = QColor(192, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 2:
first_color = QColor(0, 192, 192);
second_color = QColor(192, 0, 192);
break;
case 3:
first_color = QColor(0, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 4:
first_color = QColor(192, 0, 192);
second_color = QColor(0, 192, 192);
break;
case 5:
third_bar_width = qRound((double) bar_x / (double) SMPTE_LOWER_BARS);
int w = img.width();
int h = img.height();
int alpha = qRound(opacity_field->GetDoubleAt(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;i<SMPTE_BARS;i++) {
bar_x = bar_width*i;
switch (i) {
case 0:
first_color = QColor(192, 192, 192);
second_color = QColor(0, 0, 192);
break;
case 1:
first_color = QColor(192, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 2:
first_color = QColor(0, 192, 192);
second_color = QColor(192, 0, 192);
break;
case 3:
first_color = QColor(0, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 4:
first_color = QColor(192, 0, 192);
second_color = QColor(0, 192, 192);
break;
case 5:
third_bar_width = qRound(double(bar_x) / double(SMPTE_LOWER_BARS));
first_color = QColor(192, 0, 0);
second_color = QColor(19, 19, 19);
first_color = QColor(192, 0, 0);
second_color = QColor(19, 19, 19);
strip_width = qCeil(bar_width/SMPTE_STRIP_COUNT);
for (int j=0;j<SMPTE_STRIP_COUNT;j++) {
switch (j) {
case 0:
third_color = QColor(29, 29, 29, alpha);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), third_color);
break;
case 1:
third_color = QColor(19, 19, 19, alpha);
p.fillRect(QRect(bar_x + strip_width, third_bar_y, strip_width, third_bar_height), third_color);
break;
case 2:
third_color = QColor(9, 9, 9, alpha);
p.fillRect(QRect(bar_x, third_bar_y, strip_width, third_bar_height), third_color);
break;
}
}
break;
case 6:
first_color = QColor(0, 0, 192);
second_color = QColor(192, 192, 192);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), QColor(19, 19, 19, alpha));
break;
}
first_color.setAlpha(alpha);
second_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, 0, bar_width, first_bar_height), first_color);
p.fillRect(QRect(bar_x, first_bar_height, bar_width, second_bar_height), second_color);
}
for (int i=0;i<SMPTE_LOWER_BARS;i++) {
bar_x = third_bar_width*i;
switch (i) {
case 0: third_color = QColor(0, 33, 76); break;
case 1: third_color = QColor(255, 255, 255); break;
case 2: third_color = QColor(50, 0, 106); break;
case 3: third_color = QColor(19, 19, 19); break;
}
third_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
}
}
break;
case SOLID_TYPE_CHECKERBOARD:
{
// draw checkboard
QPainter p(&img);
img.fill(Qt::transparent);
strip_width = qCeil(bar_width/SMPTE_STRIP_COUNT);
for (int j=0;j<SMPTE_STRIP_COUNT;j++) {
switch (j) {
case 0:
third_color = QColor(29, 29, 29, alpha);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), third_color);
break;
case 1:
third_color = QColor(19, 19, 19, alpha);
p.fillRect(QRect(bar_x + strip_width, third_bar_y, strip_width, third_bar_height), third_color);
break;
case 2:
third_color = QColor(9, 9, 9, alpha);
p.fillRect(QRect(bar_x, third_bar_y, strip_width, third_bar_height), third_color);
break;
}
}
break;
case 6:
first_color = QColor(0, 0, 192);
second_color = QColor(192, 192, 192);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), QColor(19, 19, 19, alpha));
break;
}
first_color.setAlpha(alpha);
second_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, 0, bar_width, first_bar_height), first_color);
p.fillRect(QRect(bar_x, first_bar_height, bar_width, second_bar_height), second_color);
}
for (int i=0;i<SMPTE_LOWER_BARS;i++) {
bar_x = third_bar_width*i;
switch (i) {
case 0: third_color = QColor(0, 33, 76); break;
case 1: third_color = QColor(255, 255, 255); break;
case 2: third_color = QColor(50, 0, 106); break;
case 3: third_color = QColor(19, 19, 19); break;
}
third_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
}
}
break;
case SOLID_TYPE_CHECKERBOARD:
{
// draw checkboard
QPainter p(&img);
img.fill(Qt::transparent);
int checker_width = qCeil(checkerboard_size_field->get_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<QColor> 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<QColor> 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);
}
+16 -8
View File
@@ -26,17 +26,25 @@
#include <QImage>
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
+255 -243
View File
@@ -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<QTextEdit*>(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<lines.size();i++) {
QString s(lines.at(i));
if (fm.width(s) > width) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(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<lines.size();i++) {
QString s(lines.at(i));
if (fm.width(s) > width) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(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;i<lines.size();i++) {
int text_x, text_y;
for (int i=0;i<lines.size();i++) {
int text_x, text_y;
switch (halign_field->get_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;i<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
switch (halign_field->GetValueAt(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<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
// 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;
}
// 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);
}
+21 -23
View File
@@ -27,36 +27,34 @@
#include <QImage>
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
+47 -32
View File
@@ -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);
}
+9 -9
View File
@@ -27,18 +27,18 @@
#include <QImage>
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;
+36 -30
View File
@@ -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;i<nb_bytes;i+=4) {
double timecode = timecode_start+(interval*i);
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
double timecode = timecode_start+(interval*i);
qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->get_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++;
}
}
+8 -8
View File
@@ -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
+148 -181
View File
@@ -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;i<field->keyframes.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);
}
+26 -28
View File
@@ -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
+27 -28
View File
@@ -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<LabelSlider*>(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;i<nb_bytes;i+=4) {
// double vol_val = log_volume(volume_val->get_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;i<nb_bytes;i+=4) {
double vol_val = volume_val->GetDoubleAt(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;
}
}
+4 -4
View File
@@ -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
+3 -2
View File
@@ -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);
+27 -27
View File
@@ -35,42 +35,42 @@ typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t i
#include <QDialog>
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
};
+19 -5
View File
@@ -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 +=
+12 -7
View File
@@ -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;i<row->fieldCount();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;i<r->fieldCount();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<LabelSlider*>(field->ui_element));
//slider_proxy_sources.append(static_cast<LabelSlider*>(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()));
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -574,8 +574,8 @@ bool Clip::Retrieve()
int frame_size = frame->linesize[0]*frame->height;
for (int i=0;i<effects.size();i++) {
EffectPtr e = effects.at(i);
if (e->enable_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];
+816 -787
View File
File diff suppressed because it is too large Load Diff
+19 -40
View File
@@ -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);
-489
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#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 <QDateTime>
#include <QtMath>
#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.size();i++) {
if (i != key
&& ((keyframes.at(i).time > 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<LabelSlider*>(ui_element)->getPreviousValue();
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue();
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue();
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(ui_element)->getPreviousValue();
}
return QVariant();
}
QVariant EffectField::get_current_data() {
switch (type) {
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value();
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color();
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(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<LabelSlider*>(ui_element)->set_value(data.toDouble(), false);
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>());
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString());
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(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<keyframes.size();i++) {
long eval_keyframe_time = keyframes.at(i).time;
if (eval_keyframe_time == frame) {
before = i;
after = i;
return;
} else if (eval_keyframe_time < frame && eval_keyframe_time > 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<LabelSlider*>(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<QColor>();
} else {
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
QColor after_data = keyframes.at(after_keyframe).data.value<QColor>();
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<ColorButton*>(ui_element)->set_color(value);
}
break;
case EFFECT_FIELD_STRING:
if (async) {
return before_data;
}
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
break;
case EFFECT_FIELD_BOOL:
if (async) {
return before_data;
}
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
break;
case EFFECT_FIELD_COMBO:
if (async) {
return before_data;
}
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
break;
case EFFECT_FIELD_FONT:
if (async) {
return before_data;
}
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
break;
case EFFECT_FIELD_FILE:
if (async) {
return before_data;
}
static_cast<EmbeddedFileChooser*>(ui_element)->setFilename(before_data.toString());
break;
}
}
return QVariant();
}
void EffectField::ui_element_change() {
bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(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<LabelSlider*>(ui_element)->value();
}
void EffectField::set_double_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_value(v, false);
}
void EffectField::set_double_default_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_default_value(v);
}
void EffectField::set_double_minimum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_minimum_value(v);
}
void EffectField::set_double_maximum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_maximum_value(v);
}
void EffectField::add_combo_item(const QString& name, const QVariant& data) {
static_cast<ComboBoxEx*>(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<ComboBoxEx*>(ui_element)->currentIndex();
}
QVariant EffectField::get_combo_data(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentData();
}
QString EffectField::get_combo_string(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentText();
}
void EffectField::set_combo_index(int index) {
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
}
void EffectField::set_combo_string(const QString& s) {
static_cast<ComboBoxEx*>(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<QCheckBox*>(ui_element)->isChecked();
}
void EffectField::set_bool_value(bool b) {
return static_cast<QCheckBox*>(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<TextEditEx*>(ui_element)->getPlainTextEx();
}
void EffectField::set_string_value(const QString& s) {
static_cast<TextEditEx*>(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<FontCombobox*>(ui_element)->currentText();
}
void EffectField::set_font_name(const QString& s) {
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
}
QColor EffectField::get_color_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).value<QColor>();
}
validate_keyframe_data(timecode);
return static_cast<ColorButton*>(ui_element)->get_color();
}
void EffectField::set_color_value(QColor color) {
static_cast<ColorButton*>(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<EmbeddedFileChooser*>(ui_element)->getFilename();
}
void EffectField::set_filename(const QString &s) {
static_cast<EmbeddedFileChooser*>(ui_element)->setFilename(s);
}
-108
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#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 <QObject>
#include <QVariant>
#include <QVector>
#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<EffectKeyframe> 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
+12
View File
@@ -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
+20
View File
@@ -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());
}
+18
View File
@@ -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
+22
View File
@@ -0,0 +1,22 @@
#include "colorfield.h"
#include <QColor>
ColorField::ColorField(EffectRow* parent, const QString& id) :
EffectField(parent, id, EFFECT_FIELD_COLOR)
{}
QColor ColorField::GetColorAt(double timecode)
{
return GetValueAt(timecode).value<QColor>();
}
QVariant ColorField::ConvertStringToValue(const QString &s)
{
return QColor(s);
}
QString ColorField::ConvertValueToString(const QVariant &v)
{
return v.value<QColor>().name();
}
+18
View File
@@ -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
+25
View File
@@ -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();
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef COMBOFIELD_H
#define COMBOFIELD_H
#include "effectfield.h"
struct ComboFieldItem {
QString name;
QVector<QVariant> 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<ComboFieldItem> items_;
};
#endif // COMBOFIELD_H
+60
View File
@@ -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;
}
+50
View File
@@ -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
+368
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#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 <QDateTime>
#include <QtMath>
#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<EffectRow*>(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<QColor>();
} else {
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
QColor after_data = keyframes.at(after_keyframe).data.value<QColor>();
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.size();i++) {
if (i != key
&& ((keyframes.at(i).time > 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<keyframes.size();i++) {
long eval_keyframe_time = keyframes.at(i).time;
if (eval_keyframe_time == frame) {
before = i;
after = i;
return;
} else if (eval_keyframe_time < frame && eval_keyframe_time > 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<LabelSlider*>(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_);
}
+88
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#ifndef EFFECTFIELD_H
#define EFFECTFIELD_H
#include <QObject>
#include <QVariant>
#include <QVector>
#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<EffectKeyframe> 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
+22
View File
@@ -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();
}
+18
View File
@@ -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
+22
View File
@@ -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();
}
+17
View File
@@ -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
+22
View File
@@ -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();
}
+18
View File
@@ -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
+26 -23
View File
@@ -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<LabelSlider*>(x_field1->ui_element)->set_previous_value();
if (y_field1 != nullptr) static_cast<LabelSlider*>(y_field1->ui_element)->set_previous_value();
if (x_field2 != nullptr) static_cast<LabelSlider*>(x_field2->ui_element)->set_previous_value();
if (y_field2 != nullptr) static_cast<LabelSlider*>(y_field2->ui_element)->set_previous_value();
// TODO address this
/*
if (x_field1 != nullptr) static_cast<LabelSlider*>(x_field1->ui_element)->set_previous_value();
if (y_field1 != nullptr) static_cast<LabelSlider*>(y_field1->ui_element)->set_previous_value();
if (x_field2 != nullptr) static_cast<LabelSlider*>(x_field2->ui_element)->set_previous_value();
if (y_field2 != nullptr) static_cast<LabelSlider*>(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;
}
+23 -23
View File
@@ -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 <QVector>
#include <QColor>
class EffectField;
class DoubleField;
class EffectGizmo
{
public:
EffectGizmo(int type);
EffectGizmo(int type);
QVector<QPoint> world_pos;
QVector<QPoint> screen_pos;
QVector<QPoint> world_pos;
QVector<QPoint> 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
+186 -213
View File
@@ -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;i<fields.size();i++) {
delete fields.at(i);
}
for (int i=0;i<fields_.size();i++) {
delete fields_.at(i);
}
}
void EffectRow::AddField(EffectField *field)
{
field->setParent(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;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.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;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.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;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.size();j++) {
for (int i=0;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.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<EffectField*> key_fields;
QVector<int> key_field_index;
void EffectRow::ToggleKeyframe() {
QVector<EffectField*> key_fields;
QVector<int> key_field_index;
Clip* c = parent_effect->parent_clip;
for (int j=0;j<fieldCount();j++) {
EffectField* f = field(j);
for (int i=0;i<f->keyframes.size();i++) {
for (int j=0;j<fieldCount();j++) {
EffectField* f = field(j);
for (int i=0;i<f->keyframes.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;i<key_fields.size();i++) {
ca->append(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;i<key_fields.size();i++) {
ca->append(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;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.size();j++) {
for (int i=0;i<fieldCount();i++) {
EffectField* f = field(i);
for (int j=0;j<f->keyframes.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;i<fieldCount();i++) {
EffectField* f = field(i);
for (int i=0;i<fieldCount();i++) {
EffectField* f = field(i);
int exist_key = -1;
int closest_key = 0;
for (int j=0;j<f->keyframes.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;j<f->keyframes.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;i<fieldCount();i++) {
field(i)->keyframes[unsafe_keys.at(i)].data = field(i)->get_current_data();
}
for (int i=0;i<fieldCount();i++) {
field(i)->keyframes[unsafe_keys.at(i)].data = field(i)->GetCurrentValue();
}
if (ca != nullptr) {
for (int i=0;i<fieldCount();i++) {
if (key_is_new.at(i)) ca->append(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;i<fieldCount();i++) {
if (key_is_new.at(i)) ca->append(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;j<fieldCount();j++) {
EffectField* f = field(j);
for (int i=0;i<f->keyframes.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;j<fieldCount();j++) {
EffectField* f = field(j);
for (int i=0;i<f->keyframes.size();i++) {
if (f->keyframes.at(i).time == time) {
ca->append(new KeyframeDelete(f, i));
break;
}
}
}
for (int j=0;j<fieldCount();j++) {
EffectField* f = field(j);
for (int i=0;i<f->keyframes.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();
}
+37 -33
View File
@@ -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<EffectField*> fields;
QVector<QWidget*> widgets;
bool keyframing;
QGridLayout* ui;
QString name_;
int ui_row;
QVector<EffectField*> fields_;
QVector<QWidget*> widgets;
KeyframeNavigator* keyframe_nav;
KeyframeNavigator* keyframe_nav;
bool just_made_unsafe_keyframe;
QVector<int> unsafe_keys;
QVector<QVariant> unsafe_old_data;
QVector<bool> key_is_new;
bool just_made_unsafe_keyframe;
QVector<int> unsafe_keys;
QVector<QVariant> unsafe_old_data;
QVector<bool> key_is_new;
int column_count;
int column_count;
};
#endif // EFFECTROW_H
+32 -32
View File
@@ -22,45 +22,45 @@
#include <QVector>
#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<EffectField *>& selected_key_fields, QVector<int> &selected_keys) {
QVector<EffectField*> fields;
QVector<int> key_indices;
QVector<EffectField*> fields;
QVector<int> key_indices;
for (int i=0;i<selected_keys.size();i++) {
bool added = false;
for (int j=0;j<key_indices.size();j++) {
if (key_indices.at(j) < selected_keys.at(i)) {
key_indices.insert(j, selected_keys.at(i));
fields.insert(j, selected_key_fields.at(i));
added = true;
break;
}
}
if (!added) {
key_indices.append(selected_keys.at(i));
fields.append(selected_key_fields.at(i));
}
}
for (int i=0;i<selected_keys.size();i++) {
bool added = false;
for (int j=0;j<key_indices.size();j++) {
if (key_indices.at(j) < selected_keys.at(i)) {
key_indices.insert(j, selected_keys.at(i));
fields.insert(j, selected_key_fields.at(i));
added = true;
break;
}
}
if (!added) {
key_indices.append(selected_keys.at(i));
fields.append(selected_key_fields.at(i));
}
}
if (fields.size() > 0) {
ComboAction* ca = new ComboAction();
for (int i=0;i<key_indices.size();i++) {
ca->append(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;i<key_indices.size();i++) {
ca->append(new KeyframeDelete(fields.at(i), key_indices.at(i)));
}
olive::UndoStack.push(ca);
selected_keys.clear();
selected_key_fields.clear();
update_ui(false);
}
}
+18 -20
View File
@@ -42,21 +42,21 @@
#include <QCoreApplication>
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<LabelSlider*>(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";
+5 -6
View File
@@ -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
+9 -13
View File
@@ -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)
{}
+2 -2
View File
@@ -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:
+7 -5
View File
@@ -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;i<e->getIterations();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 &params) {
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 &params) {
}
}
/*
// 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 &params) {
}
}
}
*/
}
} else {
params.texture_failed = true;
+5 -5
View File
@@ -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<int> 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;i<row->fieldCount();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;j<field->keyframes.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;i<row->fieldCount();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();
+1 -1
View File
@@ -25,7 +25,7 @@
#include <QVector>
#include "project/effectrow.h"
#include "project/effectfield.h"
#include "project/effectfields.h"
QColor get_curve_color(int index, int length);
+2 -2
View File
@@ -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;k<row->fieldCount();k++) {
EffectField* f = row->field(k);
@@ -376,7 +376,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
if (panel_timeline->snapping) {
for (int i=0;i<selected_keyframes.size();i++) {
EffectField* field = selected_fields.at(i);
Clip* c = field->parent_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)) {
+3 -2
View File
@@ -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);
}
}
+10 -10
View File
@@ -24,13 +24,6 @@
#include <QLabel>
#include <QUndoCommand>
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;
+47 -17
View File
@@ -22,41 +22,71 @@
#include <QDebug>
/*
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 <QMenu>
#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);
}
}
+20 -10
View File
@@ -23,21 +23,31 @@
#include <QTextEdit>
/*
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
+5 -1
View File
@@ -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<SolidEffect*>(e.get());
solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS);
c->effects.append(e);
}
break;
+1 -1
View File
@@ -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 *)));