file/folder restructuring
This commit is contained in:
@@ -1 +0,0 @@
|
||||
Place this folder in the runtime folder of Olive.
|
||||
+1056
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,261 @@
|
||||
/***
|
||||
|
||||
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 EFFECT_H
|
||||
#define EFFECT_H
|
||||
|
||||
#include <memory>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QColor>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMouseEvent>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <random>
|
||||
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "ui/checkboxex.h"
|
||||
#include "effectfields.h"
|
||||
#include "effectrow.h"
|
||||
#include "effectgizmo.h"
|
||||
|
||||
class Clip;
|
||||
|
||||
class Effect;
|
||||
using EffectPtr = std::shared_ptr<Effect>;
|
||||
|
||||
struct EffectMeta {
|
||||
QString name;
|
||||
QString category;
|
||||
QString filename;
|
||||
QString path;
|
||||
QString tooltip;
|
||||
int internal;
|
||||
int type;
|
||||
int subtype;
|
||||
};
|
||||
extern QVector<EffectMeta> effects;
|
||||
|
||||
double log_volume(double linear);
|
||||
|
||||
enum EffectType {
|
||||
EFFECT_TYPE_INVALID,
|
||||
EFFECT_TYPE_VIDEO,
|
||||
EFFECT_TYPE_AUDIO,
|
||||
EFFECT_TYPE_EFFECT,
|
||||
EFFECT_TYPE_TRANSITION
|
||||
};
|
||||
|
||||
enum EffectKeyframeType {
|
||||
EFFECT_KEYFRAME_LINEAR,
|
||||
EFFECT_KEYFRAME_BEZIER,
|
||||
EFFECT_KEYFRAME_HOLD
|
||||
};
|
||||
|
||||
enum EffectInternal {
|
||||
EFFECT_INTERNAL_TRANSFORM,
|
||||
EFFECT_INTERNAL_TEXT,
|
||||
EFFECT_INTERNAL_SOLID,
|
||||
EFFECT_INTERNAL_NOISE,
|
||||
EFFECT_INTERNAL_VOLUME,
|
||||
EFFECT_INTERNAL_PAN,
|
||||
EFFECT_INTERNAL_TONE,
|
||||
EFFECT_INTERNAL_SHAKE,
|
||||
EFFECT_INTERNAL_TIMECODE,
|
||||
EFFECT_INTERNAL_MASK,
|
||||
EFFECT_INTERNAL_FILLLEFTRIGHT,
|
||||
EFFECT_INTERNAL_VST,
|
||||
EFFECT_INTERNAL_CORNERPIN,
|
||||
EFFECT_INTERNAL_FREI0R,
|
||||
EFFECT_INTERNAL_COUNT
|
||||
};
|
||||
|
||||
struct GLTextureCoords {
|
||||
int grid_size;
|
||||
|
||||
int vertexTopLeftX;
|
||||
int vertexTopLeftY;
|
||||
int vertexTopLeftZ;
|
||||
int vertexTopRightX;
|
||||
int vertexTopRightY;
|
||||
int vertexTopRightZ;
|
||||
int vertexBottomLeftX;
|
||||
int vertexBottomLeftY;
|
||||
int vertexBottomLeftZ;
|
||||
int vertexBottomRightX;
|
||||
int vertexBottomRightY;
|
||||
int vertexBottomRightZ;
|
||||
|
||||
float textureTopLeftX;
|
||||
float textureTopLeftY;
|
||||
float textureTopLeftQ;
|
||||
float textureTopRightX;
|
||||
float textureTopRightY;
|
||||
float textureTopRightQ;
|
||||
float textureBottomRightX;
|
||||
float textureBottomRightY;
|
||||
float textureBottomRightQ;
|
||||
float textureBottomLeftX;
|
||||
float textureBottomLeftY;
|
||||
float textureBottomLeftQ;
|
||||
|
||||
int blendmode;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
const EffectMeta* get_meta_from_name(const QString& input);
|
||||
|
||||
qint16 mix_audio_sample(qint16 a, qint16 b);
|
||||
|
||||
class Effect : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Effect(Clip *c, const EffectMeta* em);
|
||||
~Effect();
|
||||
|
||||
Clip* parent_clip;
|
||||
const EffectMeta* meta;
|
||||
int id;
|
||||
QString name;
|
||||
|
||||
void AddRow(EffectRow* row);
|
||||
|
||||
EffectRow* row(int i);
|
||||
int row_count();
|
||||
|
||||
EffectGizmo* add_gizmo(int type);
|
||||
EffectGizmo* gizmo(int i);
|
||||
int gizmo_count();
|
||||
|
||||
bool IsEnabled();
|
||||
void SetEnabled(bool b);
|
||||
|
||||
virtual void refresh();
|
||||
|
||||
virtual EffectPtr copy(Clip* c);
|
||||
void copy_field_keyframes(EffectPtr e);
|
||||
|
||||
virtual void load(QXmlStreamReader& stream);
|
||||
virtual void custom_load(QXmlStreamReader& stream);
|
||||
virtual void save(QXmlStreamWriter& stream);
|
||||
|
||||
void load_from_string(const QByteArray &s);
|
||||
QByteArray save_to_string();
|
||||
|
||||
// glsl handling
|
||||
bool is_open();
|
||||
void open();
|
||||
void close();
|
||||
bool is_glsl_linked();
|
||||
virtual void startEffect();
|
||||
virtual void endEffect();
|
||||
|
||||
enum VideoEffectFlags {
|
||||
ShaderFlag = 0x1,
|
||||
CoordsFlag = 0x2,
|
||||
SuperimposeFlag = 0x4,
|
||||
ImageFlag = 0x8
|
||||
};
|
||||
int Flags();
|
||||
void SetFlags(int flags);
|
||||
|
||||
int getIterations();
|
||||
void setIterations(int i);
|
||||
|
||||
const char* ffmpeg_filter;
|
||||
|
||||
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
|
||||
virtual void process_shader(double timecode, GLTextureCoords&, int iteration);
|
||||
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
|
||||
virtual GLuint process_superimpose(double timecode);
|
||||
virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
|
||||
virtual void gizmo_draw(double timecode, GLTextureCoords& coords);
|
||||
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done);
|
||||
void gizmo_world_to_screen();
|
||||
bool are_gizmos_enabled();
|
||||
|
||||
template <typename T>
|
||||
T randomNumber()
|
||||
{
|
||||
static std::random_device device;
|
||||
static std::mt19937 generator(device());
|
||||
static std::uniform_int_distribution<> distribution(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
||||
return distribution(generator);
|
||||
}
|
||||
|
||||
static EffectPtr Create(Clip *c, const EffectMeta *em);
|
||||
static const EffectMeta* GetInternalMeta(int internal_id, int type);
|
||||
public slots:
|
||||
void FieldChanged();
|
||||
signals:
|
||||
void EnabledChanged(bool);
|
||||
private slots:
|
||||
void delete_self();
|
||||
void move_up();
|
||||
void move_down();
|
||||
void save_to_file();
|
||||
void load_from_file();
|
||||
protected:
|
||||
// glsl effect
|
||||
QOpenGLShaderProgram* glslProgram;
|
||||
QString vertPath;
|
||||
QString fragPath;
|
||||
|
||||
// superimpose effect
|
||||
QImage img;
|
||||
QOpenGLTexture* texture;
|
||||
|
||||
bool AlwaysUpdate();
|
||||
void SetAlwaysUpdate(bool b);
|
||||
|
||||
private:
|
||||
bool isOpen;
|
||||
QVector<EffectRow*> rows;
|
||||
QVector<EffectGizmo*> gizmos;
|
||||
bool bound;
|
||||
int iterations;
|
||||
|
||||
bool enabled_;
|
||||
|
||||
int flags_;
|
||||
|
||||
// enable effect to update constantly
|
||||
bool enable_always_update_;
|
||||
|
||||
// superimpose functions
|
||||
virtual void redraw(double timecode);
|
||||
bool valueHasChanged(double timecode);
|
||||
QVector<QVariant> cachedValues;
|
||||
void delete_texture();
|
||||
void validate_meta_path();
|
||||
};
|
||||
|
||||
#endif // EFFECT_H
|
||||
@@ -0,0 +1,403 @@
|
||||
/***
|
||||
|
||||
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 <QDateTime>
|
||||
#include <QtMath>
|
||||
|
||||
#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 "rendering/renderfunctions.h"
|
||||
|
||||
#include "global/config.h"
|
||||
|
||||
#include "effects/effectrow.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include "undo/undo.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
#include "global/math.h"
|
||||
|
||||
#include "global/debug.h"
|
||||
|
||||
EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) :
|
||||
QObject(parent),
|
||||
type_(t),
|
||||
id_(i),
|
||||
enabled_(true),
|
||||
colspan_(1)
|
||||
{
|
||||
// EffectField MUST be created with a parent.
|
||||
Q_ASSERT(parent != nullptr);
|
||||
Q_ASSERT(!i.isEmpty() || t == EFFECT_FIELD_UI);
|
||||
|
||||
// Add this field to the parent row specified
|
||||
parent->AddField(this);
|
||||
|
||||
// Set a very base default value
|
||||
SetValueAt(0, 0);
|
||||
|
||||
// Connect this field to the effect's changed function
|
||||
connect(this, SIGNAL(Changed()), parent->GetParentEffect(), SLOT(FieldChanged()));
|
||||
}
|
||||
|
||||
EffectField::~EffectField() {}
|
||||
|
||||
EffectRow *EffectField::GetParentRow()
|
||||
{
|
||||
return static_cast<EffectRow*>(parent());
|
||||
}
|
||||
|
||||
int EffectField::GetColumnSpan()
|
||||
{
|
||||
return colspan_;
|
||||
}
|
||||
|
||||
void EffectField::SetColumnSpan(int i)
|
||||
{
|
||||
Q_ASSERT(i >= 1);
|
||||
colspan_ = i;
|
||||
}
|
||||
|
||||
QVariant EffectField::ConvertStringToValue(const QString &s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
QString EffectField::ConvertValueToString(const QVariant &v)
|
||||
{
|
||||
return v.toString();
|
||||
}
|
||||
|
||||
QWidget *EffectField::CreateWidget()
|
||||
{
|
||||
return new QLabel(tr("(Invalid field)"));
|
||||
}
|
||||
|
||||
void EffectField::UpdateWidgetValue(QWidget *, double) {}
|
||||
|
||||
QVariant EffectField::GetValueAt(double timecode)
|
||||
{
|
||||
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 keyframes will always return the previous keyframe with no interpolation
|
||||
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(timecodeToFrame(timecode),
|
||||
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(timecodeToFrame(timecode),
|
||||
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(timecodeToFrame(timecode),
|
||||
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 interpolation (default)
|
||||
value = double_lerp(before_dbl, after_dbl, progress);
|
||||
|
||||
}
|
||||
}
|
||||
perpetual_data_ = value;
|
||||
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));
|
||||
}
|
||||
perpetual_data_ = value;
|
||||
break;
|
||||
}
|
||||
case EFFECT_FIELD_STRING:
|
||||
case EFFECT_FIELD_BOOL:
|
||||
case EFFECT_FIELD_COMBO:
|
||||
case EFFECT_FIELD_FONT:
|
||||
case EFFECT_FIELD_FILE:
|
||||
perpetual_data_ = before_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return perpetual_data_;
|
||||
}
|
||||
|
||||
void EffectField::SetValueAt(double time, const QVariant &value)
|
||||
{
|
||||
if (HasKeyframes()) {
|
||||
|
||||
// Create keyframe here
|
||||
|
||||
// Convert seconds timecode to frame
|
||||
long frame_timecode = timecodeToFrame(time);
|
||||
|
||||
// Check array if a keyframe at this time already exists
|
||||
int keyframe_index = -1;
|
||||
for (int i=0;i<keyframes.size();i++) {
|
||||
if (keyframes.at(i).time == frame_timecode) {
|
||||
keyframe_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If keyframe doesn't exist, make it
|
||||
if (keyframe_index == -1) {
|
||||
EffectKeyframe key;
|
||||
key.time = frame_timecode;
|
||||
key.data = value;
|
||||
key.type = (keyframes.isEmpty()) ? EFFECT_KEYFRAME_LINEAR : keyframes.last().type;
|
||||
keyframes.append(key);
|
||||
} else {
|
||||
EffectKeyframe& key = keyframes[keyframe_index];
|
||||
key.data = value;
|
||||
}
|
||||
|
||||
} else {
|
||||
perpetual_data_ = value;
|
||||
}
|
||||
|
||||
emit Changed();
|
||||
}
|
||||
|
||||
double EffectField::Now()
|
||||
{
|
||||
Clip* c = GetParentRow()->GetParentEffect()->parent_clip;
|
||||
return playhead_to_clip_seconds(c, c->sequence->playhead);
|
||||
}
|
||||
|
||||
long EffectField::NowInFrames()
|
||||
{
|
||||
Clip* c = GetParentRow()->GetParentEffect()->parent_clip;
|
||||
return playhead_to_clip_frame(c, c->sequence->playhead);
|
||||
}
|
||||
|
||||
void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca)
|
||||
{
|
||||
if (enabled) {
|
||||
|
||||
// Create keyframe from perpetual data
|
||||
EffectKeyframe key;
|
||||
|
||||
key.time = NowInFrames();
|
||||
key.data = perpetual_data_;
|
||||
key.type = EFFECT_KEYFRAME_LINEAR;
|
||||
|
||||
keyframes.append(key);
|
||||
|
||||
ca->append(new KeyframeAdd(this, keyframes.size()-1));
|
||||
|
||||
} else {
|
||||
|
||||
// Convert keyframes to one "perpetual" keyframe
|
||||
|
||||
// Set first keyframe to whatever the data is now
|
||||
ca->append(new SetQVariant(&perpetual_data_, perpetual_data_, GetValueAt(Now())));
|
||||
|
||||
// Delete all keyframes
|
||||
for (int i=0;i<keyframes.size();i++) {
|
||||
ca->append(new KeyframeDelete(this, 0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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()->GetParentEffect()->parent_clip->sequence->frame_rate);
|
||||
}
|
||||
|
||||
long EffectField::timecodeToFrame(double timecode) {
|
||||
return qRound(timecode * GetParentRow()->GetParentEffect()->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.isEmpty());
|
||||
}
|
||||
|
||||
bool EffectField::IsEnabled() {
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void EffectField::SetEnabled(bool e) {
|
||||
enabled_ = e;
|
||||
emit EnabledChanged(enabled_);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/***
|
||||
|
||||
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 "effects/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,
|
||||
EFFECT_FIELD_UI
|
||||
};
|
||||
|
||||
EffectField(EffectRow* parent, const QString& i, EffectFieldType t);
|
||||
~EffectField();
|
||||
|
||||
EffectRow* GetParentRow();
|
||||
|
||||
const EffectFieldType& type();
|
||||
const QString& id();
|
||||
|
||||
QVariant GetValueAt(double timecode);
|
||||
void SetValueAt(double time, const QVariant& value);
|
||||
|
||||
double Now();
|
||||
long NowInFrames();
|
||||
|
||||
void PrepareDataForKeyframing(bool enabled, ComboAction* ca);
|
||||
|
||||
int GetColumnSpan();
|
||||
void SetColumnSpan(int i);
|
||||
|
||||
virtual QVariant ConvertStringToValue(const QString& s);
|
||||
virtual QString ConvertValueToString(const QVariant& v);
|
||||
|
||||
virtual QWidget* CreateWidget();
|
||||
virtual void UpdateWidgetValue(QWidget* widget, double);
|
||||
|
||||
double GetValidKeyframeHandlePosition(int key, bool post);
|
||||
|
||||
bool IsEnabled();
|
||||
void SetEnabled(bool e);
|
||||
|
||||
QVector<EffectKeyframe> keyframes;
|
||||
|
||||
signals:
|
||||
void Changed();
|
||||
void Clicked();
|
||||
|
||||
void EnabledChanged(bool);
|
||||
|
||||
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_;
|
||||
|
||||
QVariant perpetual_data_;
|
||||
};
|
||||
|
||||
#endif // EFFECTFIELD_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef EFFECTFIELDS_H
|
||||
#define EFFECTFIELDS_H
|
||||
|
||||
#include "fields/boolfield.h"
|
||||
#include "fields/buttonfield.h"
|
||||
#include "fields/colorfield.h"
|
||||
#include "fields/combofield.h"
|
||||
#include "fields/doublefield.h"
|
||||
#include "fields/filefield.h"
|
||||
#include "fields/fontfield.h"
|
||||
#include "fields/labelfield.h"
|
||||
#include "fields/stringfield.h"
|
||||
|
||||
#endif // EFFECTFIELDS_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/***
|
||||
|
||||
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 "effectgizmo.h"
|
||||
|
||||
#include "ui/labelslider.h"
|
||||
#include "effectfields/doublefield.h"
|
||||
#include "project/effect.h"
|
||||
|
||||
EffectGizmo::EffectGizmo(Effect *parent, int type) :
|
||||
QObject(parent),
|
||||
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)
|
||||
{
|
||||
Q_ASSERT(parent != nullptr);
|
||||
|
||||
int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1;
|
||||
world_pos.resize(point_count);
|
||||
screen_pos.resize(point_count);
|
||||
|
||||
color = Qt::white;
|
||||
}
|
||||
|
||||
void EffectGizmo::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();
|
||||
}
|
||||
|
||||
int EffectGizmo::get_type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
int EffectGizmo::get_cursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void EffectGizmo::set_cursor(int c) {
|
||||
cursor = c;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/***
|
||||
|
||||
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 EFFECTGIZMO_H
|
||||
#define EFFECTGIZMO_H
|
||||
|
||||
enum GizmoType {
|
||||
GIZMO_TYPE_DOT,
|
||||
GIZMO_TYPE_POLY,
|
||||
GIZMO_TYPE_TARGET
|
||||
};
|
||||
|
||||
#define GIZMO_DOT_SIZE 2.5
|
||||
#define GIZMO_TARGET_SIZE 5.0
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QPoint>
|
||||
#include <QVector>
|
||||
#include <QColor>
|
||||
|
||||
class DoubleField;
|
||||
class Effect;
|
||||
|
||||
class EffectGizmo : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EffectGizmo(Effect* parent, int type);
|
||||
|
||||
QVector<QPoint> world_pos;
|
||||
QVector<QPoint> screen_pos;
|
||||
|
||||
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();
|
||||
|
||||
QColor color;
|
||||
int get_point_count();
|
||||
|
||||
int get_type();
|
||||
|
||||
int get_cursor();
|
||||
void set_cursor(int c);
|
||||
private:
|
||||
int type;
|
||||
int cursor;
|
||||
};
|
||||
|
||||
#endif // EFFECTGIZMO_H
|
||||
@@ -0,0 +1,271 @@
|
||||
/***
|
||||
|
||||
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 "effectloaders.h"
|
||||
|
||||
#include "effects/effect.h"
|
||||
#include "effects/transition.h"
|
||||
#include "global/path.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "global/crossplatformlib.h"
|
||||
#include "global/config.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#ifndef NOFREI0R
|
||||
#include <frei0r.h>
|
||||
typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info);
|
||||
#endif
|
||||
|
||||
void load_internal_effects() {
|
||||
if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional";
|
||||
|
||||
EffectMeta em;
|
||||
|
||||
// load internal effects
|
||||
em.path = ":/internalshaders";
|
||||
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Volume";
|
||||
em.internal = EFFECT_INTERNAL_VOLUME;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Pan";
|
||||
em.internal = EFFECT_INTERNAL_PAN;
|
||||
effects.append(em);
|
||||
|
||||
#ifndef NOVST
|
||||
em.name = "VST Plugin 2.x";
|
||||
em.internal = EFFECT_INTERNAL_VST;
|
||||
effects.append(em);
|
||||
#endif
|
||||
|
||||
em.name = "Tone";
|
||||
em.internal = EFFECT_INTERNAL_TONE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Noise";
|
||||
em.internal = EFFECT_INTERNAL_NOISE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Fill Left/Right";
|
||||
em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT;
|
||||
effects.append(em);
|
||||
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
|
||||
em.name = "Transform";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_TRANSFORM;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Corner Pin";
|
||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||
effects.append(em);
|
||||
|
||||
/*em.name = "Mask";
|
||||
em.internal = EFFECT_INTERNAL_MASK;
|
||||
effects.append(em);*/
|
||||
|
||||
em.name = "Shake";
|
||||
em.internal = EFFECT_INTERNAL_SHAKE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Text";
|
||||
em.category = "Render";
|
||||
em.internal = EFFECT_INTERNAL_TEXT;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Timecode";
|
||||
em.internal = EFFECT_INTERNAL_TIMECODE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Solid";
|
||||
em.internal = EFFECT_INTERNAL_SOLID;
|
||||
effects.append(em);
|
||||
|
||||
// internal transitions
|
||||
em.type = EFFECT_TYPE_TRANSITION;
|
||||
em.category = "";
|
||||
|
||||
em.name = "Cross Dissolve";
|
||||
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
||||
effects.append(em);
|
||||
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Linear Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Exponential Fade";
|
||||
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Logarithmic Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
||||
effects.append(em);
|
||||
}
|
||||
|
||||
void load_shader_effects() {
|
||||
QList<QString> effects_paths = get_effects_paths();
|
||||
|
||||
for (int h=0;h<effects_paths.size();h++) {
|
||||
const QString& effects_path = effects_paths.at(h);
|
||||
QDir effects_dir(effects_path);
|
||||
if (effects_dir.exists()) {
|
||||
QList<QString> entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files);
|
||||
for (int i=0;i<entries.size();i++) {
|
||||
QFile file(effects_path + "/" + entries.at(i));
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "Could not open" << entries.at(i);
|
||||
return;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(&file);
|
||||
while (!reader.atEnd()) {
|
||||
if (reader.name() == "effect") {
|
||||
QString effect_name = "";
|
||||
QString effect_cat = "";
|
||||
const QXmlStreamAttributes attr = reader.attributes();
|
||||
for (int j=0;j<attr.size();j++) {
|
||||
if (attr.at(j).name() == "name") {
|
||||
effect_name = attr.at(j).value().toString();
|
||||
} else if (attr.at(j).name() == "category") {
|
||||
effect_cat = attr.at(j).value().toString();
|
||||
}
|
||||
}
|
||||
if (!effect_name.isEmpty()) {
|
||||
EffectMeta em;
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
em.name = effect_name;
|
||||
em.category = effect_cat;
|
||||
em.filename = file.fileName();
|
||||
em.path = effects_path;
|
||||
em.internal = -1;
|
||||
effects.append(em);
|
||||
} else {
|
||||
qCritical() << "Invalid effect found in" << entries.at(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
reader.readNext();
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_effects() {
|
||||
EffectInit* init_thread = new EffectInit();
|
||||
QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater()));
|
||||
init_thread->start();
|
||||
}
|
||||
|
||||
#ifndef NOFREI0R
|
||||
void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector<QString>& loaded_names) {
|
||||
QDir search_dir(dir);
|
||||
if (search_dir.exists()) {
|
||||
QList<QString> entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||
for (int j=0;j<entry_list.size();j++) {
|
||||
QString entry_path = search_dir.filePath(entry_list.at(j));
|
||||
if (QFileInfo(entry_path).isDir()) {
|
||||
load_frei0r_effects_worker(entry_path, em, loaded_names);
|
||||
} else {
|
||||
ModulePtr effect = LibLoad(entry_path);
|
||||
if (effect != nullptr) {
|
||||
f0rGetPluginInfo get_info_func = reinterpret_cast<f0rGetPluginInfo>(LibAddress(effect, "f0r_get_plugin_info"));
|
||||
if (get_info_func != nullptr) {
|
||||
f0r_plugin_info_t info;
|
||||
get_info_func(&info);
|
||||
|
||||
if (!loaded_names.contains(info.name)
|
||||
&& info.plugin_type == F0R_PLUGIN_TYPE_FILTER
|
||||
&& info.color_model == F0R_COLOR_MODEL_RGBA8888) {
|
||||
em.name = info.name;
|
||||
em.path = dir;
|
||||
em.filename = entry_list.at(j);
|
||||
em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename);
|
||||
|
||||
loaded_names.append(em.name);
|
||||
|
||||
effects.append(em);
|
||||
}
|
||||
// qDebug() << "Found:" << info.name << "by" << info.author;
|
||||
}
|
||||
LibClose(effect);
|
||||
}
|
||||
// qDebug() << search_dir.filePath(entry_list.at(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_frei0r_effects() {
|
||||
QList<QString> effect_dirs = get_effects_paths();
|
||||
|
||||
// add defined paths for frei0r plugins on unix
|
||||
#if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__)
|
||||
effect_dirs.prepend("/usr/lib/frei0r-1");
|
||||
effect_dirs.prepend("/usr/local/lib/frei0r-1");
|
||||
effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib");
|
||||
#endif
|
||||
|
||||
QString env_path(qgetenv("FREI0R_PATH"));
|
||||
if (!env_path.isEmpty()) effect_dirs.append(env_path);
|
||||
|
||||
QVector<QString> loaded_names;
|
||||
|
||||
// search for paths
|
||||
EffectMeta em;
|
||||
em.category = "Frei0r";
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
em.internal = EFFECT_INTERNAL_FREI0R;
|
||||
|
||||
for (int i=0;i<effect_dirs.size();i++) {
|
||||
load_frei0r_effects_worker(effect_dirs.at(i), em, loaded_names);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
EffectInit::EffectInit() {
|
||||
panel_effect_controls->effects_loaded.lock();
|
||||
}
|
||||
|
||||
void EffectInit::run() {
|
||||
qInfo() << "Initializing effects...";
|
||||
load_internal_effects();
|
||||
load_shader_effects();
|
||||
#ifndef NOFREI0R
|
||||
load_frei0r_effects();
|
||||
#endif
|
||||
panel_effect_controls->effects_loaded.unlock();
|
||||
qInfo() << "Finished initializing effects";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/***
|
||||
|
||||
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 EFFECTLOADERS_H
|
||||
#define EFFECTLOADERS_H
|
||||
|
||||
#include <QList>
|
||||
#include <QThread>
|
||||
|
||||
void init_effects();
|
||||
|
||||
class EffectInit : public QThread {
|
||||
public:
|
||||
EffectInit();
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
|
||||
#endif // EFFECTLOADERS_H
|
||||
@@ -0,0 +1,248 @@
|
||||
/***
|
||||
|
||||
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 "effectrow.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "undo/undo.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "panels/grapheditor.h"
|
||||
#include "effect.h"
|
||||
#include "ui/viewerwidget.h"
|
||||
#include "ui/keyframenavigator.h"
|
||||
#include "ui/clickablelabel.h"
|
||||
|
||||
EffectRow::EffectRow(Effect *parent, const QString &n, bool savable, bool keyframable) :
|
||||
QObject(parent),
|
||||
name_(n),
|
||||
keyframable_(keyframable),
|
||||
keyframing_(false),
|
||||
savable_(savable)
|
||||
{
|
||||
Q_ASSERT(parent != nullptr);
|
||||
|
||||
parent->AddRow(this);
|
||||
}
|
||||
|
||||
void EffectRow::AddField(EffectField *field)
|
||||
{
|
||||
field->setParent(this);
|
||||
fields_.append(field);
|
||||
}
|
||||
|
||||
bool EffectRow::IsKeyframing() {
|
||||
return keyframing_;
|
||||
}
|
||||
|
||||
void EffectRow::SetKeyframingInternal(bool b) {
|
||||
if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
keyframing_ = b;
|
||||
emit KeyframingSetChanged(keyframing_);
|
||||
}
|
||||
}
|
||||
|
||||
bool EffectRow::IsSavable()
|
||||
{
|
||||
return savable_;
|
||||
}
|
||||
|
||||
void EffectRow::SetKeyframingEnabled(bool enabled) {
|
||||
if (enabled) {
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
|
||||
// Enable keyframing setting on this row
|
||||
ca->append(new SetIsKeyframing(this, true));
|
||||
|
||||
// Prepare each field's data to start keyframing
|
||||
for (int i=0;i<FieldCount();i++) {
|
||||
Field(i)->PrepareDataForKeyframing(true, ca);
|
||||
}
|
||||
|
||||
olive::UndoStack.push(ca);
|
||||
|
||||
} else {
|
||||
|
||||
// Confirm with the user whether they really want to disable keyframing
|
||||
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) {
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
|
||||
// Prepare each field's data to stop keyframing
|
||||
for (int i=0;i<FieldCount();i++) {
|
||||
Field(i)->PrepareDataForKeyframing(false, ca);
|
||||
}
|
||||
|
||||
// Disable keyframing setting on this row
|
||||
ca->append(new SetIsKeyframing(this, false));
|
||||
|
||||
olive::UndoStack.push(ca);
|
||||
panel_effect_controls->update_keyframes();
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
SetKeyframingInternal(true);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectRow::GoToPreviousKeyframe() {
|
||||
long key = LONG_MIN;
|
||||
Clip* c = GetParentEffect()->parent_clip;
|
||||
long sequence_playhead = c->sequence->playhead;
|
||||
|
||||
// Used to convert clip frame number to sequence frame number
|
||||
long time_adjustment = c->timeline_in() - c->clip_in();
|
||||
|
||||
// Loop through all of this row's fields
|
||||
for (int i=0;i<FieldCount();i++) {
|
||||
|
||||
EffectField* f = Field(i);
|
||||
|
||||
// Loop through all of this field's keyframes for a keyframe EARLIER than the playhead
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(j).time + time_adjustment;
|
||||
|
||||
// Get the closest keyframe
|
||||
if (comp < sequence_playhead) {
|
||||
key = qMax(comp, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a keyframe less than the playhead, jump to it
|
||||
if (key != LONG_MIN) panel_sequence_viewer->seek(key);
|
||||
}
|
||||
|
||||
void EffectRow::ToggleKeyframe() {
|
||||
Clip* c = GetParentEffect()->parent_clip;
|
||||
long sequence_playhead = c->sequence->playhead;
|
||||
|
||||
// Used to convert clip frame number to sequence frame number
|
||||
long time_adjustment = c->timeline_in() - c->clip_in();
|
||||
|
||||
QVector<EffectField*> key_fields;
|
||||
QVector<int> key_field_index;
|
||||
|
||||
// See if any keyframes on any fields are at the current time
|
||||
for (int j=0;j<FieldCount();j++) {
|
||||
EffectField* f = Field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
long comp = f->keyframes.at(i).time + time_adjustment;
|
||||
|
||||
if (comp == sequence_playhead) {
|
||||
|
||||
// Cache the keyframes if they are at the current time
|
||||
key_fields.append(f);
|
||||
key_field_index.append(i);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
|
||||
if (key_fields.isEmpty()) {
|
||||
|
||||
// If we didn't find any current keyframes, create one for each field
|
||||
SetKeyframeOnAllFields(ca);
|
||||
|
||||
} else {
|
||||
|
||||
// If we DID find keyframes at this time, delete them
|
||||
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::GoToNextKeyframe() {
|
||||
long key = LONG_MAX;
|
||||
Clip* c = GetParentEffect()->parent_clip;
|
||||
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);
|
||||
}
|
||||
|
||||
void EffectRow::FocusRow() {
|
||||
panel_graph_editor->set_row(this);
|
||||
}
|
||||
|
||||
void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) {
|
||||
for (int i=0;i<FieldCount();i++) {
|
||||
EffectField* field = Field(i);
|
||||
field->SetValueAt(field->Now(), field->GetValueAt(field->Now()));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Effect *EffectRow::GetParentEffect()
|
||||
{
|
||||
return static_cast<Effect*>(parent());
|
||||
}
|
||||
|
||||
const QString &EffectRow::name() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
EffectField* EffectRow::Field(int i) {
|
||||
return fields_.at(i);
|
||||
}
|
||||
|
||||
int EffectRow::FieldCount() {
|
||||
return fields_.size();
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/***
|
||||
|
||||
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 EFFECTROW_H
|
||||
#define EFFECTROW_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
class Effect;
|
||||
class QGridLayout;
|
||||
class EffectField;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class ComboAction;
|
||||
class QHBoxLayout;
|
||||
class KeyframeNavigator;
|
||||
class ClickableLabel;
|
||||
|
||||
#include "effectfields.h"
|
||||
|
||||
class EffectRow : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EffectRow(Effect* parent, const QString& n, bool savable = true, bool keyframable = true);
|
||||
|
||||
void AddField(EffectField* Field);
|
||||
|
||||
EffectField* Field(int i);
|
||||
int FieldCount();
|
||||
void SetKeyframeOnAllFields(ComboAction *ca);
|
||||
void delete_keyframe_at_time(ComboAction *ca, long time);
|
||||
|
||||
Effect* GetParentEffect();
|
||||
|
||||
const QString& name();
|
||||
|
||||
bool IsKeyframing();
|
||||
void SetKeyframingInternal(bool);
|
||||
|
||||
bool IsSavable();
|
||||
public slots:
|
||||
void GoToPreviousKeyframe();
|
||||
void ToggleKeyframe();
|
||||
void GoToNextKeyframe();
|
||||
void FocusRow();
|
||||
signals:
|
||||
void KeyframingSetChanged(bool);
|
||||
private slots:
|
||||
void SetKeyframingEnabled(bool);
|
||||
private:
|
||||
QString name_;
|
||||
|
||||
bool keyframable_;
|
||||
bool keyframing_;
|
||||
bool savable_;
|
||||
|
||||
QVector<EffectField*> fields_;
|
||||
};
|
||||
|
||||
#endif // EFFECTROW_H
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "boolfield.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
BoolField::BoolField(EffectRow *parent, const QString &id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_BOOL)
|
||||
{}
|
||||
|
||||
bool BoolField::GetBoolAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).toBool();
|
||||
}
|
||||
|
||||
QWidget *BoolField::CreateWidget()
|
||||
{
|
||||
QCheckBox* cb = new QCheckBox();
|
||||
|
||||
connect(cb, SIGNAL(toggled(bool)), this, SLOT(UpdateFromWidget(bool)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool)));
|
||||
connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool)));
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
void BoolField::UpdateWidgetValue(QWidget *widget, double timecode)
|
||||
{
|
||||
QCheckBox* cb = static_cast<QCheckBox*>(widget);
|
||||
|
||||
// Setting the checked state on the checkbox below normally triggers a change() signal that will then trickle back
|
||||
// to setting a value on this field. Therefore we block its signals while we're setting this.
|
||||
|
||||
cb->blockSignals(true);
|
||||
|
||||
cb->setChecked(GetBoolAt(timecode));
|
||||
|
||||
cb->blockSignals(false);
|
||||
}
|
||||
|
||||
QVariant BoolField::ConvertStringToValue(const QString &s)
|
||||
{
|
||||
return (s == "1");
|
||||
}
|
||||
|
||||
QString BoolField::ConvertValueToString(const QVariant &v)
|
||||
{
|
||||
return QString::number(v.toBool());
|
||||
}
|
||||
|
||||
void BoolField::UpdateFromWidget(bool b)
|
||||
{
|
||||
SetValueAt(Now(), b);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#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 QWidget* CreateWidget() override;
|
||||
virtual void UpdateWidgetValue(QWidget* widget, double timecode) override;
|
||||
|
||||
virtual QVariant ConvertStringToValue(const QString& s) override;
|
||||
virtual QString ConvertValueToString(const QVariant& v) override;
|
||||
signals:
|
||||
void Toggled(bool);
|
||||
private slots:
|
||||
void UpdateFromWidget(bool b);
|
||||
};
|
||||
|
||||
#endif // BOOLFIELD_H
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "buttonfield.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
ButtonField::ButtonField(EffectRow *parent, const QString &string) :
|
||||
EffectField(parent, nullptr, EFFECT_FIELD_UI),
|
||||
button_text_(string)
|
||||
{}
|
||||
|
||||
void ButtonField::SetCheckable(bool c)
|
||||
{
|
||||
checkable_ = c;
|
||||
}
|
||||
|
||||
void ButtonField::SetChecked(bool c)
|
||||
{
|
||||
checked_ = c;
|
||||
emit CheckedChanged(c);
|
||||
}
|
||||
|
||||
QWidget *ButtonField::CreateWidget()
|
||||
{
|
||||
QPushButton* button = new QPushButton();
|
||||
|
||||
button->setCheckable(checkable_);
|
||||
button->setEnabled(IsEnabled());
|
||||
button->setText(button_text_);
|
||||
|
||||
connect(this, SIGNAL(CheckedChanged(bool)), button, SLOT(setChecked(bool)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), button, SLOT(setEnabled(bool)));
|
||||
connect(button, SIGNAL(clicked(bool)), this, SIGNAL(Clicked()));
|
||||
connect(button, SIGNAL(toggled(bool)), this, SLOT(SetChecked(bool)));
|
||||
connect(button, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool)));
|
||||
|
||||
return button;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef BUTTONFIELD_H
|
||||
#define BUTTONFIELD_H
|
||||
|
||||
#include "../effectfield.h"
|
||||
|
||||
class ButtonField : public EffectField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ButtonField(EffectRow* parent, const QString& string);
|
||||
|
||||
void SetCheckable(bool c);
|
||||
virtual QWidget* CreateWidget() override;
|
||||
|
||||
public slots:
|
||||
void SetChecked(bool c);
|
||||
|
||||
signals:
|
||||
void CheckedChanged(bool);
|
||||
void Toggled(bool);
|
||||
|
||||
private:
|
||||
bool checkable_;
|
||||
bool checked_;
|
||||
|
||||
QString button_text_;
|
||||
};
|
||||
|
||||
#endif // BUTTONFIELD_H
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "colorfield.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
#include "ui/colorbutton.h"
|
||||
|
||||
ColorField::ColorField(EffectRow* parent, const QString& id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_COLOR)
|
||||
{}
|
||||
|
||||
QColor ColorField::GetColorAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).value<QColor>();
|
||||
}
|
||||
|
||||
QWidget *ColorField::CreateWidget()
|
||||
{
|
||||
ColorButton* cb = new ColorButton();
|
||||
|
||||
connect(cb, SIGNAL(color_changed(const QColor &)), this, SLOT(UpdateFromWidget(const QColor &)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool)));
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
QVariant ColorField::ConvertStringToValue(const QString &s)
|
||||
{
|
||||
return QColor(s);
|
||||
}
|
||||
|
||||
QString ColorField::ConvertValueToString(const QVariant &v)
|
||||
{
|
||||
return v.value<QColor>().name();
|
||||
}
|
||||
|
||||
void ColorField::UpdateFromWidget(const QColor& c)
|
||||
{
|
||||
SetValueAt(Now(), c);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#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 QWidget* CreateWidget() override;
|
||||
|
||||
virtual QVariant ConvertStringToValue(const QString& s) override;
|
||||
virtual QString ConvertValueToString(const QVariant& v) override;
|
||||
private slots:
|
||||
void UpdateFromWidget(const QColor &c);
|
||||
};
|
||||
|
||||
#endif // COLORFIELD_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "combofield.h"
|
||||
|
||||
#include "ui/comboboxex.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 = data;
|
||||
|
||||
items_.append(item);
|
||||
}
|
||||
|
||||
QWidget *ComboField::CreateWidget()
|
||||
{
|
||||
ComboBoxEx* cb = new ComboBoxEx();
|
||||
|
||||
cb->setScrollingEnabled(false);
|
||||
|
||||
for (int i=0;i<items_.size();i++) {
|
||||
cb->addItem(items_.at(i).name);
|
||||
}
|
||||
|
||||
connect(cb, SIGNAL(activated(int)), this, SLOT(UpdateFromWidget(int)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool)));
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
void ComboField::UpdateFromWidget(int index)
|
||||
{
|
||||
SetValueAt(Now(), items_.at(index).data);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef COMBOFIELD_H
|
||||
#define COMBOFIELD_H
|
||||
|
||||
#include "../effectfield.h"
|
||||
|
||||
struct ComboFieldItem {
|
||||
QString name;
|
||||
QVariant data;
|
||||
};
|
||||
|
||||
class ComboField : public EffectField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComboField(EffectRow* parent, const QString& id);
|
||||
|
||||
void AddItem(const QString& text, const QVariant& data);
|
||||
|
||||
virtual QWidget *CreateWidget() override;
|
||||
|
||||
signals:
|
||||
void IndexChanged(int i);
|
||||
|
||||
private:
|
||||
QVector<ComboFieldItem> items_;
|
||||
|
||||
private slots:
|
||||
void UpdateFromWidget(int index);
|
||||
};
|
||||
|
||||
#endif // COMBOFIELD_H
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "doublefield.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DoubleField::DoubleField(EffectRow* parent, const QString& id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_DOUBLE),
|
||||
min_(qSNaN()),
|
||||
max_(qSNaN()),
|
||||
default_(0),
|
||||
display_type_(LabelSlider::Normal),
|
||||
frame_rate_(30),
|
||||
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());
|
||||
}
|
||||
|
||||
QWidget *DoubleField::CreateWidget()
|
||||
{
|
||||
LabelSlider* ls = new LabelSlider();
|
||||
|
||||
if (!qIsNaN(min_)) {
|
||||
ls->SetMinimum(min_);
|
||||
}
|
||||
ls->SetDefault(default_);
|
||||
if (!qIsNaN(max_)) {
|
||||
ls->SetMaximum(max_);
|
||||
}
|
||||
ls->SetDisplayType(display_type_);
|
||||
ls->SetFrameRate(frame_rate_);
|
||||
|
||||
ls->setEnabled(IsEnabled());
|
||||
|
||||
connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double)));
|
||||
connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked()));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), ls, SLOT(setEnabled(bool)));
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
void DoubleField::UpdateWidgetValue(QWidget *widget, double timecode)
|
||||
{
|
||||
static_cast<LabelSlider*>(widget)->SetValue(GetDoubleAt(timecode));
|
||||
}
|
||||
|
||||
void DoubleField::ValueHasBeenSet()
|
||||
{
|
||||
value_set_ = true;
|
||||
}
|
||||
|
||||
void DoubleField::UpdateFromWidget(double d)
|
||||
{
|
||||
SetValueAt(Now(), d);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#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);
|
||||
|
||||
virtual QWidget* CreateWidget() override;
|
||||
virtual void UpdateWidgetValue(QWidget* widget, double timecode) override;
|
||||
private:
|
||||
double min_;
|
||||
double max_;
|
||||
double default_;
|
||||
|
||||
LabelSlider::DisplayType display_type_;
|
||||
double frame_rate_;
|
||||
|
||||
bool value_set_;
|
||||
private slots:
|
||||
void ValueHasBeenSet();
|
||||
void UpdateFromWidget(double d);
|
||||
};
|
||||
|
||||
#endif // DOUBLEFIELD_H
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "filefield.h"
|
||||
|
||||
#include "ui/embeddedfilechooser.h"
|
||||
|
||||
FileField::FileField(EffectRow* parent, const QString &id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_FILE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString FileField::GetFileAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).toString();
|
||||
}
|
||||
|
||||
QWidget *FileField::CreateWidget()
|
||||
{
|
||||
EmbeddedFileChooser* efc = new EmbeddedFileChooser();
|
||||
|
||||
connect(efc, SIGNAL(changed(const QString&)), this, SLOT(UpdateFromWidget(const QString&)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), efc, SLOT(setEnabled(bool)));
|
||||
|
||||
return efc;
|
||||
}
|
||||
|
||||
void FileField::UpdateFromWidget(const QString &s)
|
||||
{
|
||||
SetValueAt(Now(), s);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#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 QWidget* CreateWidget() override;
|
||||
private slots:
|
||||
void UpdateFromWidget(const QString &s);
|
||||
};
|
||||
|
||||
#endif // FILEFIELD_H
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "fontfield.h"
|
||||
|
||||
#include <QFontDatabase>
|
||||
|
||||
#include "ui/comboboxex.h"
|
||||
|
||||
FontField::FontField(EffectRow* parent, const QString &id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_FONT)
|
||||
{
|
||||
font_list = QFontDatabase().families();
|
||||
|
||||
SetValueAt(0, font_list.first());
|
||||
}
|
||||
|
||||
QString FontField::GetFontAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).toString();
|
||||
}
|
||||
|
||||
QWidget *FontField::CreateWidget()
|
||||
{
|
||||
ComboBoxEx* fcb = new ComboBoxEx();
|
||||
|
||||
fcb->setScrollingEnabled(false);
|
||||
|
||||
fcb->addItems(font_list);
|
||||
|
||||
connect(fcb, SIGNAL(currentTextChanged(const QString &)), this, SLOT(UpdateFromWidget(const QString &)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), fcb, SLOT(setEnabled(bool)));
|
||||
|
||||
return fcb;
|
||||
}
|
||||
|
||||
void FontField::UpdateFromWidget(const QString& s)
|
||||
{
|
||||
SetValueAt(Now(), s);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#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 QWidget *CreateWidget() override;
|
||||
private:
|
||||
QStringList font_list;
|
||||
private slots:
|
||||
void UpdateFromWidget(const QString& index);
|
||||
};
|
||||
|
||||
#endif // FONTFIELD_H
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "labelfield.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
LabelField::LabelField(EffectRow *parent, const QString &string) :
|
||||
EffectField(parent, nullptr, EFFECT_FIELD_UI),
|
||||
label_text_(string)
|
||||
{}
|
||||
|
||||
QWidget *LabelField::CreateWidget()
|
||||
{
|
||||
QLabel* label = new QLabel(label_text_);
|
||||
|
||||
label->setEnabled(IsEnabled());
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), label, SLOT(setEnabled(bool)));
|
||||
|
||||
return label;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef LABELFIELD_H
|
||||
#define LABELFIELD_H
|
||||
|
||||
#include "../effectfield.h"
|
||||
|
||||
class LabelField : public EffectField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LabelField(EffectRow* parent, const QString& string);
|
||||
|
||||
virtual QWidget* CreateWidget() override;
|
||||
private:
|
||||
QString label_text_;
|
||||
};
|
||||
|
||||
#endif // LABELFIELD_H
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "stringfield.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
#include "ui/texteditex.h"
|
||||
#include "global/config.h"
|
||||
|
||||
StringField::StringField(EffectRow* parent, const QString& id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_STRING)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString StringField::GetStringAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).toString();
|
||||
}
|
||||
|
||||
QWidget *StringField::CreateWidget()
|
||||
{
|
||||
TextEditEx* text_edit = new TextEditEx();
|
||||
|
||||
text_edit->setEnabled(IsEnabled());
|
||||
text_edit->setUndoRedoEnabled(true);
|
||||
|
||||
// the "2" looks like a magic number, but it's just one pixel on the top and the bottom
|
||||
text_edit->setFixedHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines
|
||||
+ text_edit->document()->documentMargin()
|
||||
+ text_edit->document()->documentMargin() + 2));
|
||||
|
||||
connect(text_edit, SIGNAL(textModified(const QString&)), this, SLOT(UpdateFromWidget(const QString&)));
|
||||
connect(this, SIGNAL(EnabledChanged(bool)), text_edit, SLOT(setEnabled(bool)));
|
||||
|
||||
return text_edit;
|
||||
}
|
||||
|
||||
void StringField::UpdateFromWidget(const QString &s)
|
||||
{
|
||||
SetValueAt(Now(), s);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#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 QWidget *CreateWidget() override;
|
||||
private slots:
|
||||
void UpdateFromWidget(const QString& b);
|
||||
};
|
||||
|
||||
#endif // STRINGFIELD_H
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef AUDIONOISEEFFECT_H
|
||||
#define AUDIONOISEEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class AudioNoiseEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
#include "cornerpineffect.h"
|
||||
|
||||
#include "io/path.h"
|
||||
#include "project/clip.h"
|
||||
#include "debug.h"
|
||||
#include "global/path.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
SetFlags(Effect::CoordsFlag & Effect::ShaderFlag);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef CORNERPINEFFECT_H
|
||||
#define CORNERPINEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class CornerPinEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef CROSSDISSOLVETRANSITION_H
|
||||
#define CROSSDISSOLVETRANSITION_H
|
||||
|
||||
#include "project/transition.h"
|
||||
#include "effects/transition.h"
|
||||
|
||||
class CrossDissolveTransition : public Transition {
|
||||
public:
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef CUBETRANSITION_H
|
||||
#define CUBETRANSITION_H
|
||||
|
||||
#include "project/transition.h"
|
||||
#include "effects/transition.h"
|
||||
|
||||
class CubeTransition : public Transition {
|
||||
public:
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#ifndef EXPONENTIALFADETRANSITION_H
|
||||
#define EXPONENTIALFADETRANSITION_H
|
||||
|
||||
#include "project/transition.h"
|
||||
#include "effects/transition.h"
|
||||
|
||||
class ExponentialFadeTransition : public Transition {
|
||||
public:
|
||||
ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
};
|
||||
|
||||
#endif // LINEARFADETRANSITION_H
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef FILLLEFTRIGHTEFFECT_H
|
||||
#define FILLLEFTRIGHTEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class FillLeftRightEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
|
||||
#include "project/clip.h"
|
||||
#include "timeline/clip.h"
|
||||
|
||||
typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height);
|
||||
typedef int (*f0rInitFunc) ();
|
||||
|
||||
@@ -23,32 +23,31 @@
|
||||
|
||||
#ifndef NOFREI0R
|
||||
|
||||
#include "project/effect.h"
|
||||
|
||||
#include <frei0r.h>
|
||||
|
||||
#include "io/crossplatformlib.h"
|
||||
#include "effects/effect.h"
|
||||
#include "global/crossplatformlib.h"
|
||||
|
||||
typedef void (*f0rGetParamInfo)(f0r_param_info_t * info,
|
||||
int param_index );
|
||||
int param_index );
|
||||
|
||||
class Frei0rEffect : public Effect {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
Frei0rEffect(Clip* c, const EffectMeta* em);
|
||||
~Frei0rEffect();
|
||||
~Frei0rEffect();
|
||||
|
||||
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
|
||||
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
|
||||
|
||||
virtual void refresh();
|
||||
virtual void refresh();
|
||||
private:
|
||||
ModulePtr handle;
|
||||
f0r_instance_t instance;
|
||||
int param_count;
|
||||
f0rGetParamInfo get_param_info;
|
||||
void destruct_module();
|
||||
void construct_module();
|
||||
bool open;
|
||||
ModulePtr handle;
|
||||
f0r_instance_t instance;
|
||||
int param_count;
|
||||
f0rGetParamInfo get_param_info;
|
||||
void destruct_module();
|
||||
void construct_module();
|
||||
bool open;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#ifndef LINEARFADETRANSITION_H
|
||||
#define LINEARFADETRANSITION_H
|
||||
|
||||
#include "project/transition.h"
|
||||
#include "effects/transition.h"
|
||||
|
||||
class LinearFadeTransition : public Transition {
|
||||
public:
|
||||
LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
};
|
||||
|
||||
#endif // LINEARFADETRANSITION_H
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#ifndef LOGARITHMICFADETRANSITION_H
|
||||
#define LOGARITHMICFADETRANSITION_H
|
||||
|
||||
#include "project/transition.h"
|
||||
#include "effects/transition.h"
|
||||
|
||||
class LogarithmicFadeTransition : public Transition {
|
||||
public:
|
||||
LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
};
|
||||
|
||||
#endif // LOGARITHMICFADETRANSITION_H
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef PANEFFECT_H
|
||||
#define PANEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class PanEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -27,11 +27,10 @@
|
||||
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "panels/timeline.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
SetFlags(Effect::CoordsFlag);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef SHAKEEFFECT_H
|
||||
#define SHAKEEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#define RANDOM_VAL_SIZE 30
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <QImage>
|
||||
#include <QComboBox>
|
||||
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
const int SMPTE_BARS = 7;
|
||||
const int SMPTE_STRIP_COUNT = 3;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef SOLIDEFFECT_H
|
||||
#define SOLIDEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "ui/colorbutton.h"
|
||||
#include "ui/fontcombobox.h"
|
||||
#include "io/config.h"
|
||||
#include "global/config.h"
|
||||
|
||||
TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
|
||||
Effect(c, em)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef TEXTEFFECT_H
|
||||
#define TEXTEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QImage>
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "ui/colorbutton.h"
|
||||
#include "ui/fontcombobox.h"
|
||||
#include "io/config.h"
|
||||
#include "global/config.h"
|
||||
|
||||
TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) :
|
||||
Effect(c, em)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef TIMECODEEFFECT_H
|
||||
#define TIMECODEEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QImage>
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
|
||||
#define TONE_TYPE_SINE 0
|
||||
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "debug.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
|
||||
EffectRow* type_row = new EffectRow(this, tr("Type"));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef TONEEFFECT_H
|
||||
#define TONEEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class ToneEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -30,14 +30,14 @@
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "project/footage.h"
|
||||
#include "io/math.h"
|
||||
#include "global/math.h"
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "panels/project.h"
|
||||
#include "debug.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
#include "panels/panels.h"
|
||||
#include "panels/viewer.h"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef TRANSFORMEFFECT_H
|
||||
#define TRANSFORMEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class TransformEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <QFile>
|
||||
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "debug.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) {
|
||||
QString display_name;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* isn't lost if the user saves over the project.
|
||||
*/
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class VoidEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -34,7 +34,7 @@ VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
|
||||
// set defaults
|
||||
volume_val->SetDefault(1);
|
||||
volume_val->SetDisplayType(LabelSlider::LABELSLIDER_DECIBEL);
|
||||
volume_val->SetDisplayType(LabelSlider::Decibel);
|
||||
}
|
||||
|
||||
void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef VOLUMEEFFECT_H
|
||||
#define VOLUMEEFFECT_H
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
class VolumeEffect : public Effect {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include <QWindow>
|
||||
|
||||
#include "rendering/audio.h"
|
||||
#include "mainwindow.h"
|
||||
#include "debug.h"
|
||||
#include "ui/mainwindow.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <X11/X.h>
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#ifndef NOVST
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include "io/crossplatformlib.h"
|
||||
#include "global/crossplatformlib.h"
|
||||
|
||||
#include "include/vestige.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/***
|
||||
|
||||
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 "keyframe.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include "effectfields.h"
|
||||
#include "undo/undo.h"
|
||||
#include "panels/panels.h"
|
||||
|
||||
EffectKeyframe::EffectKeyframe()
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/***
|
||||
|
||||
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 KEYFRAME_H
|
||||
#define KEYFRAME_H
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
class EffectField;
|
||||
|
||||
class EffectKeyframe {
|
||||
public:
|
||||
EffectKeyframe();
|
||||
|
||||
int type;
|
||||
long time;
|
||||
QVariant data;
|
||||
|
||||
// only for bezier type
|
||||
double pre_handle_x;
|
||||
double pre_handle_y;
|
||||
double post_handle_x;
|
||||
double post_handle_y;
|
||||
};
|
||||
|
||||
void delete_keyframes(QVector<EffectField *> &selected_key_fields, QVector<int> &selected_keys);
|
||||
|
||||
#endif // KEYFRAME_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user